Использование типа "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.