Использование типа "var" в объявлении переменной

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

Я не знаю никакой разницы между явным объявлением типа и использование var после компиляции кода в MSIL.

18 ответов


как насчет этого...

double GetTheNumber()
{
    // get the important number from somewhere
}

а затем в другом месте...

var theNumber = GetTheNumber();
DoSomethingImportant(theNumber / 5);

и затем, в какой-то момент в будущем, кто-то замечает это GetTheNumber только когда-либо возвращает целые числа так, переделывает его, чтобы вернуть int, а не double.

Ура! Нет ошибок компилятора, и вы начинаете видеть неожиданные результаты, потому что то, что раньше было арифметикой с плавающей запятой, теперь стало целочисленной арифметикой, и никто этого не заметил.

сказав, что, такого рода вещи должны быть пойманным вашими модульными тестами и т. д., Но это все еще потенциальный gotcha.


Я склонен следовать этой схеме:

var myObject = new MyObject(); // OK as the type is clear

var myObject = otherObject.SomeMethod(); // Bad as the return type is not clear

Если тип возврата SomeMethod когда-либо изменяется, тогда этот код все равно будет компилироваться. В лучшем случае вы получите ошибку компиляции дальше, но в худшем случае (в зависимости от того, как myObject используется) Вы не могли. То, что вы, вероятно, получите в этом случае, это ошибки во время выполнения, которые могут быть очень трудно отследить.


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

var myDouble = 2;
var myHalf = 1 / myDouble;

очевидно, это ошибка, а не "неожиданный результат". Но это!--5-- > is грубо...


var не является динамическим типом, это просто синтаксический сахар. Единственное исключение-анонимные типы. из Microsoft Docs

во многих случаях использование var является необязательным и является просто синтаксическим удобством. Однако при инициализации переменной с анонимным типом необходимо объявить переменную как var, если требуется получить доступ к свойствам объекта в более поздний момент.

нет никакой разницы после компиляции в IL если вы явно не определили тип, отличный от того, который будет подразумеваться (хотя я не могу придумать, почему вы). Компилятор не позволит вам изменить тип переменной, объявленной с помощью var в любой момент.

с документация Microsoft (снова)

неявно типизированная локальная переменная строго типизирована так же, как если бы вы тип, но компилятор определяет тип

в некоторых случаях ВАР может impeed читабельности. Больше Microsoft docs состояние:

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


в неуниверсальных мире вы можете получить различное поведение при использовании var вместо типа всякий раз, когда произойдет неявное преобразование, например, в foreach петли.

в приведенном ниже примере неявное преобразование из object до XmlNode имеет место (non-generic IEnumerator интерфейс возвращает только object). Если вы просто замените явное объявление переменной цикла на var ключевое слово, это неявное преобразование не требуется место:

using System;
using System.Xml;

class Program
{
    static void Foo(object o)
    {
        Console.WriteLine("object overload");
    }

    static void Foo(XmlNode node)
    {
        Console.WriteLine("XmlNode overload");
    }

    static void Main(string[] args)
    {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml("<root><child/></root>");

        foreach (XmlNode node in doc.DocumentElement.ChildNodes)
        {
            Foo(node);
        }

        foreach (var node in doc.DocumentElement.ChildNodes)
        {
            // oops! node is now of type object!
            Foo(node);
        }
    }
}

в результате этот код фактически производит разные выходы в зависимости от того, используете ли вы var или явный тип. С var на Foo(object) перегрузка будет выполнена, в противном случае Foo(XmlNode) перегрузка будет. Таким образом, вывод вышеуказанной программы:

XmlNode overload
object overload

обратите внимание, что это поведение идеально соответствует спецификации языка C#. Единственная проблема в том, что var выводит другой тип (object) чем вы ожидали бы и что этот вывод не очевиден из взгляда на код.

Я не добавил IL, чтобы сохранить его коротким. Но если вы хотите, вы можете посмотреть с ildasm, чтобы увидеть, что компилятор фактически генерирует разные инструкции IL для двух циклов foreach.


Это странное утверждение, что с помощью var никогда не следует использовать, поскольку он "может привести к неожиданным результатам в некоторых случаях", потому что есть тонкости в языке C# намного сложнее, чем использование var.

один из них-детали реализации анонимных методов, которые могут привести к предупреждению R# "доступ к измененному закрытию" и поведению, которое очень не то, что вы могли бы ожидать от просмотра кода. В отличие от var Что можно объяснить в пару из предложений это поведение занимает три длинных сообщения в блоге, которые включают выход дизассемблера, чтобы полностью объяснить:

это означает, что вы также не должны использовать анонимные методы (т. е. делегаты, лямбды) и библиотеки, которые полагаются на них, такие как Linq или ParallelFX, только потому, что при определенных странных обстоятельствах поведение может быть не таким, как вы ожидаете?

конечно, нет.

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

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


Они утверждают, что использование var " может привести к неожиданным результатам в некоторых случаях".к неожиданным результатам в некоторых случаях".

Если неожиданным является "я не знаю, как читать код и выяснить, что он делает", то да, это может привести к неожиданным результатам. Компилятор должен знать, какой тип сделать переменной на основе кода, написанного вокруг переменной.

ключевое слово var является функцией времени компиляции. Компилятор поместит в соответствующий тип для объявления. Вот почему вы не можете делать такие вещи, как:

var my_variable = null
or
var my_variable;

ключевое слово var отлично, потому что вам нужно определить меньше информации в самом коде. Компилятор выясняет, что он должен сделать для вас. Это почти как всегда Программирование интерфейса при его использовании (где методы и свойства интерфейса определяются тем, что вы используете в пространстве объявления переменной, определенной var). Если тип переменной должен изменение (в пределах разумного, конечно), вам не нужно беспокоиться об изменении объявления переменной, компилятор обрабатывает это для вас. Это может показаться тривиальным, но что произойдет, если вам нужно изменить возвращаемое значение в функции, и эта функция используется во всей программе. Если вы не использовали var, то вам нужно найти и заменить каждое место, которое вызывается переменной. С ключевым словом var вам не нужно беспокоиться об этом.


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

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

Я лично люблю var. Я использую его для всех локальных переменных. Все время. Если результирующий тип не ясен, то это не проблема с var, но проблема с (именованием) методов, используемых для инициализации переменной...


Я следую простому принципу, когда дело доходит до использования ключевого слова var. Если вы знаете тип заранее, не используйте var. В большинстве случаев я использую var с linq, поскольку могу захотеть вернуть анонимный тип.


var лучше всего использовать, когда у вас есть явно объявление

ArrayList<Entity> en = new ArrayList<Enity>()

усложняет читабельность

var en = new ArrayList<Entity>()

ленивый, четкий код, мне это нравится


Я использую var только там, где ясно, какой тип переменной, или где нет необходимости знать тип вообще (например, GetPerson () должен возвращать Person, Person_Class, etc.).

Я не использую var для примитивных типов enum, и строки. Я также не использую его для типа значения, потому что тип значения будет скопирован назначением, поэтому тип переменной должен быть объявлен явно.

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


использование var-это ленивый код, если вы знаете, каким будет тип. Его просто легче и проще читать. При взгляде на много и много кода, проще и чище всегда лучше


нет абсолютно никакой разницы в выходе IL для объявления переменной с помощью var и один явно указано (Вы можете доказать это с помощью отражателя). Я обычно использую только var для длинных вложенных универсальных типов,foreach циклы и анонимные типы, поскольку мне нравится, чтобы все было явно указано. У других могут быть другие предпочтения.


var - это просто сокращенное обозначение использования явного объявления типа.

вы можете использовать var только в определенных обстоятельствах; вам придется инициализировать переменную во время объявления при использовании var. После этого переменной нельзя назначить переменную другого типа.

Мне кажется, что многие люди склонны путать ключевое слово " var "с типом данных "Variant" в VB6 .


" единственное " преимущество, которое я вижу в использовании явного объявления переменных, - это хорошо выбранные имена типов, которые вы указываете на намерение вашего фрагмента кода намного яснее (что важнее всего остального imo). Преимущество var-ключевого слова действительно то, что сказал Питер.


Я также думаю, что вы столкнетесь с проблемами, если объявите своих двойников без D в конце. когда вы компилируете версию выпуска, ваш компилятор, скорее всего, очистит double и сделает их float для экономии места, поскольку он не будет учитывать вашу точность.


var будет компилироваться так же, как и статический тип, который может быть указан. Это просто устраняет необходимость быть явным с этим типом в вашем коде. Он не является динамическим типом и не может/не может изменяться во время выполнения. Я считаю, что это очень полезно использовать в циклах foreach.

foreach(var item in items)
{
item.name = ______;
}

при работе с перечислениями несколько раз определенный тип неизвестен времени поиска. Использование VAR вместо статического типа yeald тот же результат. Я также обнаружил, что использование var одалживает его для облегчения рефакторинга. Когда используется перечисление другого типа, foreach не нужно будет обновлять.


использование var может скрыть ошибки логического программирования, которые в противном случае вы получили бы предупреждение от компилятора или IDE. См. этот пример:

float distX = innerDiagramRect.Size.Width / (numObjInWidth + 1);

здесь все типы в расчете являются int, и вы получаете предупреждение о возможной потере фракции, потому что вы получаете результат в float переменной.

использование var:

var distX = innerDiagramRect.Size.Width / (numObjInWidth + 1);

здесь вы не получите никакого предупреждения, потому что тип distX компилируется как int. Если вы намеревались использовать float значения, это логическая ошибка, которая скрыта для вас, и трудно обнаружить при выполнении, если он не вызывает divide by zero исключение в более позднем вычислении, если результат этого начального вычисления