Я не понимаю вариант использования шаблонов var в C # 7. MSDN:

Сопоставление с шаблоном var всегда завершается успешно. Его синтаксис

expr is var varname

где значение expr всегда присваивается локальной переменной с именем varname . varname является статической переменной того же типа, что и expr.

На мой взгляд, пример с MSDN довольно бесполезен, особенно потому, что if избыточен:

object[] items = { new Book("The Tempest"), new Person("John") };
foreach (var item in items) {
  if (item is var obj)
    Console.WriteLine($"Type: {obj.GetType().Name}, Value: {obj}"); 
}

Здесь я не вижу никаких преимуществ, вы могли бы получить то же самое, если бы вы обращались к переменной цикла item напрямую, которая также имеет тип Object. if также сбивает с толку, потому что это никогда не false.

Я мог бы использовать var otherItem = item или использовать item напрямую. Может кто-нибудь лучше объяснить вариант использования?

30
Tim Schmelter 23 Фев 2018 в 14:01

4 ответа

Лучший ответ

Шаблон var очень часто обсуждался в репозитории языка C #, поскольку совершенно ясно, каков его вариант использования, и учитывая тот факт, что is var x не выполняет нулевую проверку, в то время как is T x делает, что делает его довольно бесполезным.

Однако на самом деле он не предназначен для использования в качестве obj is var x. Он предназначен для использования, когда левая часть не сама по себе является переменной.

Вот несколько примеров из спецификации. Все они используют функции, которых пока нет в C # , но это просто показывает, что введение шаблона var было в основном сделано при подготовке к этим вещам, поэтому им не придется больше к нему обращаться позже.

В следующем примере объявляется функция Deriv для создания производной функции с использованием структурного шаблона сопоставление в дереве выражений:

Expr Deriv(Expr e)
{
    switch (e) {
        // …
        case Const(_): return Const(0);
        case Add(var Left, var Right):
            return Add(Deriv(Left), Deriv(Right));
        // …
}

Здесь шаблон var может использоваться внутри структур для «извлечения» элементов из структуры. Аналогично, следующий пример упрощает выражение:

Expr Simplify(Expr e)
{
    switch (e) {
        case Mult(Const(0), _): return Const(0);
        // …
        case Add(Const(0), var x): return Simplify(x);
    }
}

Как пишет здесь, идея также состоит в том, чтобы сопоставлять шаблоны свойств, позволяя следующее:

if (o is Point {X is 3, Y is var y})
{ … }
16
poke 23 Фев 2018 в 13:48

Не проверяя заметки по дизайну на Github, я думаю, что это было добавлено больше для согласованности с switch и как ступенька для более сложных случаев сопоставления с образцом,

Из оригинальных Что нового в C # 7.0 сообщение:

Шаблоны var в форме var x (где x - это идентификатор), которые всегда совпадают, и просто помещают значение ввода в новую переменную x того же типа, что и ввод.

И недавний анализ пост Сергея Теплякова:

если вы знаете, что именно происходит, вы можете найти эту модель полезной. Его можно использовать для введения временной переменной внутри выражения: этот шаблон по существу создает временную переменную, используя фактический тип объекта.

public void VarPattern(IEnumerable<string> s)
{
    if (s.FirstOrDefault(o => o != null) is var v
        && int.TryParse(v, out var n))
    {
        Console.WriteLine(n);
    }
}

Предупреждение перед этим фрагментом также имеет значение:

Непонятно, почему поведение отличается только в режиме Release. Но я думаю, что все проблемы сводятся к одному и тому же: начальная реализация функции является неоптимальной. Но на основании этого комментария Нила Гафтера это изменится: «Код понижения соответствия шаблонов переписывается с нуля (для поддержки рекурсивных шаблонов тоже). Я ожидаю, что большинство улучшений, которые вы здесь ищите, будут бесплатными» msgstr "в новом коде. Но пройдет еще какое-то время, прежде чем этот перезапись будет готова для прайм-тайма."

По словам Кристиана Нагеля:

Преимущество состоит в том, что переменная, объявленная с ключевым словом var, имеет реальный тип объекта,

14
Panagiotis Kanavos 23 Фев 2018 в 13:15

В большинстве случаев это правда, польза от шаблона var не ясна и может даже быть плохой идеей. Однако, как способ захвата анонимных типов во временной переменной, он прекрасно работает. Надеемся, что этот пример может проиллюстрировать это: Обратите внимание, что добавление нулевого регистра позволяет избежать того, чтобы var всегда был нулевым, и проверка нуля не требуется.

        var sample = new(int id, string name, int age)[] { 
                                                          (1, "jonas", 50),                                                                                                                            
                                                          (2, "frank", 48) };

        var f48 = from s in sample 
                  where s.age == 48 
                  select new { Name = s.name, Age = s.age };

        switch(f48.FirstOrDefault())
        {
            case var choosen when choosen.Name == "frank":
                WriteLine(choosen.Age);
                break;
            case null:
                WriteLine("not found");
                break;
        }
0
Jonas Brandel 3 Апр 2018 в 11:17

Единственное, что я могу придумать, это то, что вы написали два идентичных блока кода (скажем, один switch), один для expr is object a, а другой для expr is null.

Вы можете объединить блоки, переключившись на expr is var a.

Это также может быть полезно в сценариях генерации кода, когда по какой-либо причине вы уже записали себя в угол и всегда ожидаете сгенерировать сопоставление с образцом, но теперь хотите выпустить шаблон «сопоставить все».

1
Damien_The_Unbeliever 23 Фев 2018 в 12:44