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

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

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

Аудитор - уважаемый профессионал, поэтому я не могу просто отказаться от такого предложения.

Ответ 1

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

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

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

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

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

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

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

Ответ 2

Я стараюсь следовать этой схеме:

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

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

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

В некоторых случаях var может считывать удобочитаемость. Подробнее Документы Microsoft:

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

Ответ 5

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

В приведенном ниже примере происходит неявное преобразование из object в XmlNode (только для универсального интерфейса 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

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

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

Ответ 6

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

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

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

Конечно, нет.

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

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

Ответ 7

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

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

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

var my_variable = null
or
var my_variable;

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

Ответ 8

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

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

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

Ответ 9

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

Ответ 10

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

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

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

var en = new ArrayList<Entity>()

Ленивый, понятный код, мне нравится

Ответ 11

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

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

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

Ответ 12

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

Ответ 13

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

Ответ 14

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

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

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

Ответ 15

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

Ответ 16

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

Ответ 17

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

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

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

Ответ 18

Использование 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 в более позднем вычислении, если результат этого начального вычисления равен < 1.