Использование ключевого слова var в C #

406

После обсуждения с коллегами относительно использования ключевого слова 'var' в C # 3 мне стало интересно, что люди думают о правильном использовании вывода типа через var?

Например, я довольно лениво использовал var в сомнительных обстоятельствах, например:

foreach(var item in someList) { // ... } // Type of 'item' not clear.
var something = someObject.SomeProperty; // Type of 'something' not clear.
var something = someMethod(); // Type of 'something' not clear.

Более законные варианты использования var:

var l = new List<string>(); // Obvious what l will be.
var s = new SomeClass(); // Obvious what s will be.

Интересно, что LINQ выглядит немного серым, например:

var results = from r in dataContext.SomeTable
              select r; // Not *entirely clear* what results will be here.

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

Еще хуже, когда речь идет о LINQ для объектов, например:

var results = from item in someList
              where item != 3
              select item;

Это не лучше, чем эквивалентный foreach (var item в someList) {// ...} эквивалентный.

Здесь существует реальная проблема безопасности типов - например, если бы мы поместили результаты этого запроса в перегруженный метод, который принимал IEnumerable <int> и IEnumerable <double>, вызывающая сторона могла бы непреднамеренно передать неправильный тип.

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

ljs
источник
68
Использование var - это хорошо, но «мне не нужно выяснять тип» кажется очень плохой причиной для его использования ... вы должны знать, что это за тип, var - просто ярлык, чтобы избежать его ввода
Томас Левеск
53
var i = 0;== провал! var c = new CrazyFrigginLongClassName();== победить!
dotjoe
6
«Var также напоминает мне вариантный тип VB / VBA. Он также имел свое место. Я помню (много лет назад) его использование было менее желательным, и он был довольно ресурсоемким». <- показывает, что это вопрос приманки, так как тип C # 'var' не имеет ничего общего с типом варианта VB / VBA.
user7116
20
var readabilityBeDamned = true;
Спулсон
9
Проблема всех приведенных здесь примеров заключается в том, что мы смотрим на одну строку кода. Когда я вижу строку за строкой объявлений "var", одно за другим, это выходит из-под контроля. Читаемость субъективна, но я считаю, что вар злоупотребляет гораздо больше, чем пользуется уважением.
Jro

Ответы:

293

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

var orders = cust.Orders;

Меня не волнует , если Customer.Orders есть IEnumerable<Order>, ObservableCollection<Order>или BindingList<Order>- все , что я хочу, чтобы сохранить этот список в памяти для итерации по нему или получить его счет или что - то позже.

Сравните приведенную выше декларацию с:

ObservableCollection<Order> orders = cust.Orders;

Для меня имя типа просто шум. И если я вернусь и решу изменить тип Customer.Orders вниз по дорожке (скажем, от ObservableCollection<Order>до IList<Order>), то мне нужно тоже изменить это объявление - что-то, что мне не пришлось бы делать, если бы я использовал var в первом место.

Мэтт Гамильтон
источник
48
Мне нравится иметь явный тип передо мной, когда я читаю код. Как я узнаю, что такое "cust.Orders" здесь без типа? Да, я мог бы навести курсор мыши, чтобы узнать, но зачем мне это нужно? :)
Джон Tackabury
77
Но дело в том, что в целом это не имеет значения. При условии, cust.Orders - это то, что вы можете перечислить (например, foreach over), тогда не имеет значения, какой это тип. Дополнительный код просто мешает чтению намерения.
Мэтт Гамильтон
67
Но если вам требуется только, чтобы cust.Orders был «чем-то, что вы можете перечислить», то не объявит ли его как IEnumerable <Order>, сделать это требование явным и ясным? Объявление его как var означает, что вы фактически потеряете это требование.
GrahamS
5
@jon, и как IEnumerbal orders = cust.Orders foreach (порядок var в ордерах) будет иметь значение? IEnumerable говорит только о том, что вы можете поместить его в foreach, но вы уже знали об этом из строки ниже
Rune FS
18
«Единственное, что говорит IEnumerable - это то, что вы можете поместить его в foreach», - это также выражает намерение, что единственное, что вы можете сделать, это перечислить. Использование var дает доступ и intellisense для открытых членов конкретного типа коллекции.
Джо
167

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

Правда, это может означать, что не ясно, с каким типом мы имеем дело. И что? Это на самом деле точка развязанного дизайна. Имея дело с интерфейсами, вы решительно не интересуетесь типом переменной. varправда, это гораздо дальше, но я думаю, что аргумент остается неизменным с точки зрения читабельности: программист должен интересоваться не типом переменной, а тем, что делает переменная . Вот почему Microsoft также называет вывод типа «утка».

Итак, что делает переменная, когда я объявляю ее используя var? Легко, он делает то, что мне говорит IntelliSense. Любые рассуждения о C #, которые игнорируют IDE, не соответствуют действительности. На практике каждый код C # программируется в среде IDE, которая поддерживает IntelliSense.

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

Теперь команда C # выпустила руководство по кодированию, в котором говорится, что его varследует использовать только для захвата результата оператора LINQ, который создает анонимный тип (потому что здесь у нас нет реальной альтернативы var). Ну, винт это. Пока команда C # не дает мне веских аргументов в пользу этого руководства, я буду игнорировать его, потому что, по моему профессиональному и личному мнению, это чистый вздор. (Извините, у меня нет ссылки на данный вопрос.)

На самом деле, есть несколько (поверхностно) хороших объяснений того, почему вы не должны их использовать, varно я все еще считаю, что они в значительной степени ошибочны. Возьмите пример «searchabililty»: автор утверждает, что varзатрудняет поиск мест, где MyTypeон используется. Правильно. Так же и интерфейсы. На самом деле, почему я хотел бы знать, где используется класс? Возможно, меня больше интересует, где он создается, и он все равно будет доступен для поиска, потому что где-то должен вызываться его конструктор (даже если это делается косвенно, имя типа должно упоминаться где-то).

Конрад Рудольф
источник
14
В любой приличной IDE вы не используете текстовый поиск для получения использования класса, вы получаете IDE, чтобы сделать это на основе его дерева разбора или, в противном случае, он идентифицирует типы объектов. Поскольку мы говорим о статической типизации, здесь будут найдены все, кроме анонимных типов.
Dustman
6
Я бы не хотел наследовать 100 тыс. Строк исходного кода без документации и свободного использования var. Особенно, если вы комбинируете var с менее чем полезными именами переменных. Я мог бы увидеть, что это полезно при иллюстрации точки (или при работе с анонимными типами), но в рабочем коде?
Ши
7
Арнши: хорошо, вы уже указали на реальную проблему: бесполезные имена переменных и недостающую документацию . Я действительно не вижу, что varспособствует путанице. Конечно, могут быть случаи, когда важно подчеркнуть тип / размер переменной (например, операции с битами низкого уровня). Это нормально: никто никогда не утверждал, что varдолжен использоваться исключительно. Правило простое: если оно действительно вызывает путаницу, не используйте его.
Конрад Рудольф
17
Каждый пример, противоположный var, который я видел, предполагает, что программист будет использовать бессмысленные имена переменных. Но, возможно, именно поэтому var лучше, чем явное указание типа: это заставляет программиста придумывать правильные имена переменных.
Райан Ланди
16
Microsoft также называет вывод типа «утка». - они действительно? Я был бы в шоке ...
Антон Тихий
118

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

С моей точки зрения, использование хороших соглашений об именах для переменных и методов более важно с точки зрения читабельности, чем явная информация о типах. Если мне нужна информация о типе, я всегда могу навести курсор на переменную (в VS) и получить ее. Как правило, однако, явная информация о типе не должна быть необходимой для читателя. Для разработчика в VS вы по-прежнему получаете Intellisense, независимо от того, как объявлена ​​переменная. Сказав все это, все еще могут быть случаи, когда имеет смысл явно объявить тип - возможно, у вас есть метод, который возвращает a List<T>, но вы хотите рассматривать его какIEnumerable<T>в вашем методе. Чтобы убедиться, что вы используете интерфейс, объявление переменной типа интерфейса может сделать это явным. Или, возможно, вы хотите объявить переменную без начального значения - потому что она сразу же получает значение на основе некоторого условия. В этом случае вам нужен тип. Если информация о типе полезна или необходима, используйте ее. Однако я чувствую, что, как правило, в этом нет необходимости, и в большинстве случаев код легче читать без него.

tvanfosson
источник
3
Я согласен в целом. Ключевой момент здесь, на мой взгляд, должен быть уверен, что намерение ясно. Если это не понятно большинству разработчиков в команде, то это вредно, а не полезно. Тем не менее, я лично ОГРОМНЫЙ поклонник этого, но мне пришлось немного обуздать себя, когда другие разработчики в моей команде не смогли определить мои намерения. Пойди разберись.
Стив Бруйяр
3
Эх, мне легче читать, когда шрифт слева. Используя ReSharper, мне все равно не нужно перепечатывать шрифт справа, так что это меня не беспокоит.
BlueRaja - Дэнни Пфлюгофт
1
@BlueRaja - Я считаю, что использование хороших имен переменных, как правило, избавляет от необходимости беспокоиться о реальном типе для понимания. Intellisense по-прежнему доступен для переменных, определенных «var», поэтому мне не нужно знать тип, чтобы выбрать метод / свойство для него при кодировании.
tvanfosson
2
Дело не столько в том, когда вы кодируете, сколько в том, когда вы должны читать код.
BlueRaja - Дэнни Пфлюгофт
1
Тогда я просто должен быть в стороне, мне нужны хорошие методы и имена переменных, а также понимание типов, с которыми нужно работать, чтобы правильно понять код, который я читаю. Я думаю, что вы правы, хотя это симптом более серьезных проблем. Один из доверия. Чтобы быть уверенным в том, что код делает то, что он делает, вы должны быть уверены в используемых типах.
AnthonyWJones
91

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

  1. Тип анонимный (ну, здесь у вас нет выбора, так как в этом случае он должен быть var)
  2. Тип очевиден в зависимости от назначенного выражения (т.е. var foo = new TypeWithAReallyLongNameTheresNoSenseRepeating())

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

Адам Робинсон
источник
1
согласен с обоими, хотя у меня есть длинные ограничения во втором случае, если тип такой длинный, то обычно это универсальный тип с множеством вложенных универсальных аргументов, в этом случае строго типизированный «ShortType, эквивалентный TypeWithAReallyLongNameTheresNoSenseRepeating» имеет больше смысла
Ion Todirel
12
У меня нет желания начинать религиозную войну, но я, как правило, не согласен с Ионом. Я бы предпочел очень длинное, но очень точное имя типа (аля дядя Боб Мартин), чем сокращенное и, возможно, неоднозначное более короткое имя типа. Я добавлю оговорку, с которой я не согласен, искусственно завышая длину имени. Если 5 символов создают краткое имя, которое ясно показывает намерение, тогда используйте 5, а не 25.
Стив Бруйяр
2
@ Стив: Я должен согласиться с вами; создание «короткого типа» (который я предполагаю, что вы имеете в виду наследование от определенного универсального типа исключительно для сокращения имени) не является хорошей практикой; это потребует от вас дублирования и прохождения через любые конструкторы из универсального типа, а также запретит вам передавать другой тип, который наследует от универсального типа, в функцию. Вы используете наследство как typedefкогда это не так.
Адам Робинсон
7
Использовать, varкогда тип очевиден? Возможно, но истинная выгода - это когда тип не имеет значения. Если вы делаете подобные вещи, var customers = whatever; var query = from c in customers select stuffне имеет значения, какой именно тип «клиентов». Понятно, как это можно использовать, и этого достаточно. И если фактический тип громоздок, стоит его подавить.
Джорен
2
@Kristoffer: я могу понять, что хочу избавиться от путаницы тегов, но перенос их в класс не является (IMO) приемлемой альтернативой, так как тогда вы исключаете возможность того, чтобы любой другой (законный) дочерний класс этого универсального типа был действительный параметр. Я бы предпочел использовать using ShortType = LongGenericType<A,B,C>директиву в верхней части файла, поскольку она обеспечивает одинаковую читаемость, не требует повторного создания конструкторов и не исключает дочерние классы из числа кандидатов.
Адам Робинсон
68

От Эрика Липперта, старшего инженера-разработчика программного обеспечения в команде C #:

Почему было varвведено ключевое слово?

Есть две причины, одна из которых существует сегодня, другая появится в версии 3.0.

Первая причина в том, что этот код невероятно уродлив из-за всей избыточности:

Dictionary<string, List<int>> mylists = new Dictionary<string, List<int>>();

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

var mylists = new Dictionary<string,List<int>>();

и пусть компилятор выяснит, какой тип основан на присваивании.

Во-вторых, C # 3.0 вводит анонимные типы. Поскольку анонимные типы по определению не имеют имен, вы должны иметь возможность вывести тип переменной из инициализирующего выражения, если ее тип является анонимным.

Акцент мой. Целая статья, C # 3.0 все еще статически напечатана, честно! и последующие серии довольно хороши.

Это для чего var. Другое использование, вероятно, не будет работать так хорошо. Любое сравнение с JScript, VBScript или динамической типизацией является полной накладкой. Примечание снова, varэто требуется для того , чтобы иметь некоторые другие особенности работы в .NET.

Dustman
источник
Я нахожу аргумент Липперта странным. Никто не вводит имя второго класса, они позволяют Intellisense написать его для них, но затем он оборачивается и заявляет, что var лучше, потому что компилятор / Intellisense решает его. Вы не можете иметь это в обоих направлениях!
Дэйв
5
Команда C # не контролирует intellisense, она контролирует компилятор. В любом случае это не главная проблема. Я не думаю, что вар набрал бы 100 баллов за сохранение печатания в одиночку.
Пылесос
@ Dustman: вар вообще не сохраняет набрав. Это заставляет вас писать больше!
Петр Перак
53

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

У меня нет проблем с использованием var в выражении foreach при условии, что это не так:

foreach (var c in list) { ... }

Если бы это было больше так:

foreach (var customer in list) { ... }

... тогда кто-то, читающий код, с большей вероятностью поймет, что такое «список». Если у вас есть контроль над именем самой переменной списка, это даже лучше.

То же относится и к другим ситуациям. Это довольно бесполезно:

var x = SaveFoo(foo);

... но это имеет смысл:

var saveSucceeded = SaveFoo(foo);

Кажется, каждому свое. Я обнаружил, что делаю это, что просто безумие:

var f = (float)3;

Мне нужна какая-то 12-шаговая вар-программа. Меня зовут Мэтт, и я (ab) использую вар.

Мэтт Гамильтон
источник
6
Ну, единственное, что не так с "var f = (float) 3;" в том, что это должно быть "var f = 3f" или "var f = 3.0 (вызывает отстой одинарной точности)".
MichaelGG
3
Хех да 3f или 3.0 это путь! Мы, вар маньяки, должны держаться вместе!
Мэтт Гамильтон
27
Настоящая проблема в этом первом примере - это «список», а не «с». «список» чего ? «список» должен быть переименован в «клиенты», или «клиенты, кто платит деньги», или «текущие клиенты», или что-то гораздо более наглядное. И когда у вас есть это, «с» может оставаться как есть, потому что вы уже знаете, что он будет содержать.
Райан Ланди
4
Привет Мэтт! Меня зовут Кенни, и я вараддикт.
Кенни
var MattHamil = "Люк Скайуокер"; // снял с себя тонну
Binoj Antony
40

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

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

Таким образом,

var something = SomeMethod();

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

var list = new List<KeyValuePair<string, double>>();
FillList( list );
foreach( var item in list ) {
   DoWork( item ); 
}
Декстер
источник
4
Я обнаружил, что («Код для людей, а не машин») является отличным руководством - следование ему может привести к улучшению кода и поможет избежать преждевременной оптимизации.
Танатос
3
Я не получаю var list = new KeyValuePair <string, double>? Для меня список может иметь больше, чем на вещи.
TTT
«Код для людей, а не машин» - аминь.
user1068352 12.12.12
39

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

Другой случай, вызывающий беспокойство, в следующем вызове вы не можете определить, просто посмотрев код, возвращаемый типом CallMe:

var variable = CallMe();

Это моя главная жалоба на вар.

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

var callback = new Func<IntPtr, bool>(delegate(IntPtr hWnd) {
   ...
});

РЕДАКТИРОВАТЬ : Обновлен последний пример кода на основе ввода Джулиана

Ион Тодирель
источник
3
Но вам действительно нужно знать тип прямо в этой строке? Вы знаете, что CallMe что-то возвращает; Разве недостаточно знать, что создана локальная переменная с именем variable? Если вы не расширите свой пример, это не очень серьезная жалоба, ИМО.
Рандольфо
2
Дело не в том, чтобы не быть многословным, а в том, чтобы компилятор не делал для вас синтаксический сахар. Рассмотрим это: var getter ..., теперь это Func <object> getter ..., со вторым, которое вы знаете, вам не нужно предоставлять никаких параметров и что оно возвращает. Вы с самого начала знаете, «что делать» и можете быстрее принимать решения, разрабатывая что-либо или проводя рефакторинг. Наличие всей информации под рукой важнее, чем еще несколько символов. Это можно оценить только тогда, когда вы работаете с большим количеством кода.
Ион Тодирел
2
Так как в любом случае мы все говорим о визуальной студии, что такого значительного в том, чтобы навести курсор мыши на переменную на секунду и просто посмотреть, какой это тип? В любом случае, намного лучше, чем бежать к декларации.
Рубис
3
Общие имена переменных и функций ( variable, CallMe) являются плохими примерами. Однако, если бы это CallMe()была функция в каком-то «телефонном приложении», var call = CallMe(); .... call.HangUp();это имело бы гораздо больший смысл.
Данко Дурбич
3
@Randolpho: "Что такого особенного в том, чтобы навести курсор мыши на переменную на секунду и просто посмотреть, какой это тип?" Это добавляет время к накладным расходам на обслуживание ... плюс одна секунда - это только время наведения мыши, а не подсчет переключателя контекста с клавиатуры на мышь. Я не знаю о вас, но я работаю с крайним сроком. Каждый раз, когда мне нужно навести курсор на переменную, чтобы выяснить, к какому типу она относится, лучше потратить время на исправление проблемы.
Powerlord
36

Var совсем не похож на вариант. Переменная все еще строго типизирована, просто вы не нажимаете клавиши, чтобы получить ее таким образом. Вы можете навести на него курсор в Visual Studio, чтобы увидеть тип. Если вы читаете напечатанный код, возможно, вам придется немного подумать, чтобы понять, что это за тип. Но есть только одна строка, которая объявляет это, и много строк, которые его используют, так что присвоение приличных имен - все еще лучший способ облегчить выполнение вашего кода.

Использование Intellisense лениво? Он меньше печатает, чем целое имя. Или есть вещи, которые меньше работают, но не заслуживают критики? Я думаю, что есть, и Вар является одним из них.

Кейт Грегори
источник
6
+1, единственный человек, который должен отметить, что не varимеет ничего общего с Variant.
user7116
27

Скорее всего, вам понадобится это время для анонимных типов (где это требуется на 100%); но это также избегает повторения для тривиальных случаев, и IMO делает линию более четкой. Мне не нужно видеть тип дважды для простой инициализации.

Например:

Dictionary<string, List<SomeComplexType<int>>> data = new Dictionary<string, List<SomeComplexType<int>>>();

(пожалуйста, не редактируйте hscroll выше - это как бы доказывает смысл !!!)

против:

var data = new Dictionary<string, List<SomeComplexType<int>>>();

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

static void DoSomething(IFoo foo) {Console.WriteLine("working happily") }
static void DoSomething(Foo foo) {Console.WriteLine("formatting hard disk...");}

// this working code...
IFoo oldCode = new Foo();
DoSomething(oldCode);
// ...is **very** different to this code
var newCode = new Foo();
DoSomething(newCode);
Marc Gravell
источник
1
(для информации, вы можете получить аналогичные проблемы в любом случае, где это неявное преобразование типов)
Марк Гравелл
1
Не соглашайтесь с тем, что вы не хотите видеть его дважды в одной строке. Возможно, что в будущем вы не создадите переменную напрямую после объявления (например, в случае, если ниже определения), чем может быть неясно, что это за тип. Большинство разработчиков привыкли видеть тип непосредственно в начале строки, особенно в сложном коде, который не нужно затруднять чтением кода.
Гертьян
@TheVillageIdiot - я откатил ваши правки, потому что в этом случае hscroll связан с точкой ;-p
Марк
2
@Gertjan - мой мозг ограничен; если это сложно, я не хочу видеть это дважды и должен начать сравнение (интерфейс / конкретный / и т. д.). Я счастлив увидеть это однажды и подумать «напечатан как один из них».
Марк Гравелл
17

Один конкретный случай, когда var сложен: проверка автономного кода, особенно те, которые сделаны на бумаге.

Вы не можете полагаться на наведение мыши для этого.

Джон Лимджап
источник
17
Какого черта ты рецензируешь код на бумаге? Думай о деревьях! ;)
Dustman
8
Вы можете иметь ту же проблему, не используя var. Проблема не в вар; проблема в плохих именах переменных. Если имена переменных выбраны правильно, использование var не имеет значения.
Райан Ланди
В моей команде есть парень, который просматривает его собственный код и ищет ошибки, печатая его код. Его стены покрыты кодом. Однажды я вошел, и у него была целая большая доска, покрытая одним из его отладочных упражнений. Это было, вероятно, ~ 10000 LOC
звуковой сигнал
Только имена переменных не решают проблему, если вы не вернетесь к венгерской нотации, где тип является частью имени.
Кевин Гейл,
17

Я не понимаю, в чем дело ..

var something = someMethod(); // Type of 'something' not clear <-- not to the compiler!

У вас все еще есть полная интеллигентность по «чему-то», и для любого неоднозначного случая у вас есть свои юнит-тесты, верно? ( вы? )

Это не varchar, это не тусклый, и это, конечно, не динамическая или слабая типизация. Это останавливает maddnes как это:

List<somethinglongtypename> v = new List<somethinglongtypename>();

и уменьшая эту общую суматоху до:

var v = new List<somethinglongtypename>();

Хорошо, не так хорошо, как:

v = List<somethinglongtypename>();

Но тогда для этого и нужен Бу .

Frep D-Oronge
источник
тип «что-то» очень понятен компилятору, внутренне «var» устанавливается на тип возврата «someMethod», он понятен компилятору, но может быть неясен для разработчиков, работающих над проектом. и Бу быстро растет на меня
Стивенбайер
Нет, v = List<somethinglongtypename>();даже лучше. Важно различать введение новой переменной и присвоение существующей переменной.
HighCommander4
Хорошо, если вы уже присвоили 'v' в текущей области видимости, то это присваивание существующему. В противном случае это присвоение новой переменной 'v'. Легко.
Frep D-Oronge
17

Если кто-то использует varключевое слово, потому что он не хочет «выяснить тип», это определенно неправильная причина. varКлючевое слово не создает переменную с типом динамического, компилятор все равно должен знать тип. Поскольку переменная всегда имеет определенный тип, этот тип также должен быть очевиден в коде, если это возможно.

Хорошие причины использовать varключевое слово, например:

  • Где это необходимо, т.е. объявить ссылку на анонимный тип.
  • Где это делает код более читабельным, т.е. удаляет повторяющиеся объявления.

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

Guffa
источник
11

Учитывая, насколько мощным теперь является Intellisense, я не уверен, что var сложнее для чтения, чем наличие переменных-членов в классе или локальных переменных в методе, которые определены вне видимой области экрана.

Если у вас есть строка кода, такая как

IDictionary<BigClassName, SomeOtherBigClassName> nameDictionary = new Dictionary<BigClassName, SomeOtherBigClassName>();

Гораздо проще или труднее читать, чем:

var nameDictionary = new Dictionary<BigClassName, SomeOtherBigClassName>();
Колин Десмонд
источник
На самом деле я не рассматривал это, как видно из другого вопроса, который является довольно сильным аргументом для другого использования.
Финглас
По сути, это была единственная причина, по которой они реализовали это (помимо возможности объявлять анонимные типы, но они могли сделать «var» специальным ключевым словом, предназначенным только для анонимных типов.)
mqp
10

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

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

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

Другая вещь , чтобы помнить о том , что его не тип VB вар в том , что он не может изменить тип - это является строго типизированным переменным его только что тип выводятся (поэтому есть люди , которые будут утверждать , что его не неразумно используйте его, скажем, в foreach, но я не согласен по причинам как удобочитаемости, так и удобства обслуживания).

Я подозреваю, что этот собирается бежать и бежать (-:

Murph

Murph
источник
10

Конечно, intэто легко, но когда тип переменной IEnumerable<MyStupidLongNamedGenericClass<int, string>>, var делает вещи намного проще.

Blorgbeard отсутствует
источник
2
+1 за это. intПротив этого varесть что поспорить, но множественные вложенные универсальные типы делают varнаходку. Именно здесь использование имени типа снова и снова нарушает читабельность кода.
Крис Фармер
Это абсолютно неправильная причина для его использования. Если ваш код использует вложенный универсальный тип, вы должны получить для него определенный именованный класс. Например: class IntStringEnumerator : IEnumerable<MyStupidLongNamedGenericClass<int, string>>и затем используйте новое имя. Это очищает код и лучше описывает тип.
xxbbcc
Хорошо, но мой пример был просто гиперболой. IntStringEnumerator i = new IntStringEnumerator()все еще слишком много печатать.
Blorgbeard отсутствует
9

Похищен из поста по этому вопросу на CodingHorror :


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

MyObject m = new ();

Или, если вы передаете параметры:

Person p = new ("FirstName", "LastName);

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

В конце концов, это просто не было предназначено для сокращения избыточности. Не поймите меня неправильно, «var» ОЧЕНЬ важен в C # для анонимных типов / проекций, но использование здесь просто ОТКЛЮЧЕНО (и я говорил это очень долго), когда вы запутываете тип, который используется. Потребность напечатать это дважды - слишком часто, но объявлять это нулем - слишком мало.

Николас Палдино .NET / C # MVP 20 июня 2008 г. 08:00


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

Если вы когда-нибудь станете человеком, который смотрит на ваш код, то кого это волнует? В противном случае, в таком случае:

var people = Managers.People

это хорошо, но в таком случае:

var fc = Factory.Run();

он замыкает любые непосредственные выводы типа, которые мой мозг может начать формировать из «английского» кода.

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

Ростов
источник
4
Приведенные выше примеры не являются аргументом для отказа от использования var; они являются аргументом для использования хороших описательных имен переменных. Если бы вместо [var fc = Factory.Run ();] у вас было [bool fc = Factory.Run ();], код не стал бы более понятным.
Райан Ланди
9

Использование varвместо явного типа значительно упрощает рефакторинг (поэтому я должен противоречить предыдущим постерам, которые имели в виду, что это не имеет значения, или это был просто «синтаксический сахар»).

Вы можете изменить тип возврата ваших методов, не меняя каждый файл, где вызывается этот метод. Представить

...
List<MyClass> SomeMethod() { ... }
...

который используется как

...
IList<MyClass> list = obj.SomeMethod();
foreach (MyClass c in list)
  System.Console.WriteLine(c.ToString());
...

Если вы хотите выполнить рефакторинг SomeMethod()для возврата IEnumerable<MySecondClass>, вам придется изменять объявление переменной (также внутри foreach) в каждом месте, где вы использовали метод.

Если ты пишешь

...
var list = obj.SomeMethod();
foreach (var element in list)
  System.Console.WriteLine(element.ToString());
...

вместо этого вам не нужно это менять.

MartinStettner
источник
согласился - интересно, почему этот приятный побочный эффект не так часто рекламируется, как некоторые другие, более субъективные плюсы в более популярных ответах.
fieldingmellish
Это случилось со мной сегодня. У меня есть фабричный класс, который возвращает значение класса MainMenu. Сегодня я создал MainMenu2 с тем же интерфейсом MainMenu. У меня весь код приложения нетронутым после изменения!
Марко Стаффоли
8

@aku: Одним из примеров являются обзоры кода. Другой пример - сценарии рефакторинга.

По сути, я не хочу охотиться за типами с помощью мыши. Это может быть недоступно.

erlando
источник
2
Интересно, вы говорите это, потому что var может упростить рефакторинг. Если вы использовали var, вам не нужно. Теперь вы всегда можете положиться на инструменты рефакторинга в IDE, но знаете, вы всегда можете рассчитывать на IDE и для типа :)
Фред,
8

Это вопрос вкуса. Все эти разговоры о типе переменной исчезают, когда вы привыкаете к языкам с динамической типизацией. То есть, если они вам когда-нибудь начнут нравиться (я не уверен, что все могут, но мне это нравится).

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

Тип вашей переменной не так уж важен (об этом уже говорилось). Это должно быть относительно ясно из контекста (его взаимодействия с другими переменными и методами) и его имени - не ожидайте, что customerList будет содержать int...

Я все еще жду, чтобы увидеть, что мой босс думает по этому поводу - я получил общее предложение «использовать» в 3.5 новые конструкции, но что мы будем делать с техническим обслуживанием?

Дарен Томас
источник
7

При сравнении между вами IEnumerable<int>и IEnumerable<double>вам не нужно беспокоиться - если вы передадите неверный тип, ваш код все равно не скомпилируется.

Там нет заботы о безопасности типов, так как неvar является динамическим. Это просто магия компилятора, и любые небезопасные вызовы, которые вы делаете, будут пойманы.

Var абсолютно необходим для Linq:

var anonEnumeration =
    from post in AllPosts()
    where post.Date > oldDate
    let author = GetAuthor( post.AuthorId )
    select new { 
        PostName = post.Name, 
        post.Date, 
        AuthorName = author.Name
    };

Теперь посмотрите на anonEnumeration в intellisense, и он будет выглядеть примерно так:IEnumerable<'a>

foreach( var item in anonEnumeration ) 
{
    //VS knows the type
    item.PostName; //you'll get intellisense here

    //you still have type safety
    item.ItemId;   //will throw a compiler exception
}

Компилятор C # довольно умен - все типы, сгенерированные отдельно, будут иметь одинаковый сгенерированный тип, если их свойства совпадают.

Помимо этого, если у вас есть intellisense, имеет смысл использовать varвезде, где ясен контекст.

//less typing, this is good
var myList = new List<UnreasonablyLongClassName>();

//also good - I can't be mistaken on type
var anotherList = GetAllOfSomeItem();

//but not here - probably best to leave single value types declared
var decimalNum = 123.456m;
Кейт
источник
Пожалуйста, IQueriable<T>удалите, прежде чем повторять: anonEnumeration.ToList();
Дэвид Диез
@DavidDiez не могли бы вы перефразировать? Ваше утверждение не имеет смысла. Ни одна из моих ссылок на фрагменты кода IQueryableили.ToList()
Кит
var anonEnumeration = from post in AllPosts() where post.Date > oldDate let author = GetAuthor( post.AuthorId ) select new { PostName = post.Name, post.Date, AuthorName = author.Name };не возвращает IQueriable<T>?
Дэвид Диез
1
@DavidDiez это зависит от того, что AllPosts()возвращает - спрашивает спрашивающий, List<T>поэтому я предположил, что. В этом случае результатом anonEnumerationбудет тип IEnumerable<'a>. Теперь, если вместо этого AllPosts()возвращается, IQueryable<T>то anonEnumerationстанет IQueryable<'a>(обратите внимание, нет iв Queryable) - однако в этом случае мой код все еще работает, потому что IQueryable<T>реализует IEnumerable<T>. Здесь есть множество лучших вопросов и ответов о различиях между ними - здесь мой случай - это 'aанонимность и varпозволяет вам присвоить его статически типизированной переменной.
Кит
Ох, я вижу, спасибо за объяснение :) Мой комментарий был, потому что итерация IQueryable<T>не является хорошей практикой, потому что на каждой итерации вы делаете оператор чтения в БД. Обязательно перед *.ToList() IQueryable<T>тем, как их повторить
Дэвид Диез
7

Я думаю, это зависит от вашей точки зрения. Лично у меня никогда не было трудностей с пониманием фрагмента кода из-за var«неправильного использования», и я и мои коллеги используем его довольно часто. (Я согласен, что Intellisense является огромной помощью в этом отношении.) Я приветствую это как способ устранения повторяющихся ошибок.

В конце концов, если заявления как

var index = 5; // this is supposed to be bad

var firstEligibleObject = FetchSomething(); // oh no what type is it
                                            // i am going to die if i don't know

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

MQP
источник
Предположительно в .Net 4, где динамические типы являются обычным явлением, это станет более важным?
Колин Десмонд
2
Напротив, если вас сейчас смущает «var», я бы ожидал, что вас дополнительно смущает «динамический». Не дай Бог, кто-нибудь когда-либо объявит динамику, а затем сделает ссылку на нее, используя "var" :)
mqp
Я имел в виду что-то вроде динамического d = 52; var x = d; что должно быть хорошо.
Mqp
7

Я использую var только тогда, когда ясно, какой тип используется.

Например, я бы использовал var в этом случае, потому что вы сразу видите, что x будет иметь тип «MyClass»:

var x = new MyClass();

Я бы НЕ использовал var в таких случаях, потому что вам нужно навести курсор мыши на код и посмотреть на всплывающую подсказку, чтобы увидеть, какой тип возвращает MyFunction:

var x = MyClass.MyFunction();

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

var x = 5;

(потому что компилятор не может знать, хочу ли я байта, short, int или что-то еще)

Кристиан Шпехт
источник
Если правая сторона не достаточно ясна, чтобы оправдать использование var, то varпроблема не в этом: проблема в правой стороне. Это не достаточно описательно . Customer c = GetContext()до сих пор неясно и не лучше, чем использовать var.
JulianR
6

Для меня антипатия к varиллюстрации иллюстрирует важность двуязычия в .NET. Для тех программистов на C #, которые также работали с VB .NET, преимущества varочевидны. Стандартное объявление C #:

List<string> whatever = new List<string>();

это эквивалентно, в VB .NET, набирать это:

Dim whatever As List(Of String) = New List(Of String)

Никто не делает это в VB .NET, хотя. Было бы глупо, потому что начиная с первой версии .NET вы смогли сделать это ...

Dim whatever As New List(Of String)

... который создает переменную и инициализирует ее в одну достаточно компактную строку. Ах, но что, если вы хотите IList<string>, а не List<string>? Ну, в VB .NET это означает, что вы должны сделать это:

Dim whatever As IList(Of String) = New List(Of String)

Точно так же, как вы должны делать в C #, и, очевидно, не можете использовать varдля:

IList<string> whatever = new List<string>();

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

Райан Ланди
источник
1
Забавно, что вы упоминаете двуязычие как нечто, способствующее использованию вар. Мой антагонизм по отношению к ключевому слову var проистекает из моего свободного владения javascript! :)
Urig
varв C # не имеет никакого отношения varк JavaScript. var-Declared переменной в C # сильно типизированных.
Райан Ланди
6

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

Те, кто говорит: «Неважно, используйте то, что вам нравится», не видят всей картины. Каждый в тот или иной момент подберет чужой код, и ему придется иметь дело с любыми решениями, которые они приняли во время написания. Достаточно плохо иметь дело с радикально различными соглашениями об именах или - с классическими стилями захвата, без добавления всего « varили нет» в микс. В худшем случае один программист не использовал его, varа затем приходит сопровождающий, который любит его и расширяет код, используя его. Так что теперь у вас нечестивый беспорядок.

Стандарты - это хорошая вещь именно потому, что они означают, что у вас гораздо больше шансов получить случайный код и быстро его получить. Чем больше вещей отличаются, тем сложнее становится. И переход к стилю «везде» имеет большое значение.

Я не против динамической типизации, и я не против имплицитной типизации - в языках, которые предназначены для них. Мне очень нравится Python. Но C # был задуман как статически явно типизированный язык, и так оно и должно быть. Нарушение правил для анонимных типов было достаточно плохо; Позволить людям пойти дальше и сломать идиомы языка еще больше - это то, что меня не устраивает. Теперь, когда джинна нет в бутылке, он никогда не вернется. C # будет балканизирован в лагеря. Фигово.

Нил Хьюитт
источник
7
Ух ты. Игнорирование всех аргументов, приведенных в этой теме до сих пор, и перестановка всей дискуссии - настоящее достижение.
Конрад Рудольф
Это 100% описывает, как я отношусь к «var», особенно с точки зрения выбора чужого кода. Использование var радикально меняет задачу под рукой, если она засорена повсюду. +1
Саймон
6

Много раз во время тестирования я обнаруживал, что у меня есть такой код:

var something = myObject.SomeProperty.SomeOtherThing.CallMethod();
Console.WriteLine(something);

Теперь, иногда, я хочу посмотреть, что содержит само SomeOtherThing, SomeOtherThing не того типа, который возвращает CallMethod (). Так как я использую var, я просто изменяю это:

var something = myObject.SomeProperty.SomeOtherThing.CallMethod();

к этому:

var something = myObject.SomeProperty.SomeOtherThing;

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

BFree
источник
6

Для любителей, которые думают, что varэкономит время, требуется меньше нажатий клавиш для ввода:

StringBuilder sb = new StringBuilder();

чем

var sb = new StringBuilder();

Считай их, если не веришь мне ...

19 против 21

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

И это верно для каждого типа, о котором вы можете подумать !!

Мое личное мнение состоит в том, что никогда не следует использовать var, за исключением случаев, когда тип неизвестен, поскольку он уменьшает распознаваемость в коде. Мозгу требуется больше времени, чтобы распознать тип, чем полная строка. Старые таймеры, которые понимают машинный код и биты, точно знают, о чем я говорю. Мозг обрабатывает параллельно, и когда вы используете var, вы заставляете его сериализовать свой ввод. Почему кто-то хочет заставить свой мозг работать усерднее? Вот для чего компьютеры.

Wray Smallwood
источник
Я считаю повторение stringBuilder sb = new StringBuilder () грязным и длинным, чтобы его можно было четко распознать. Это дополнительный шум. Проблема в том, что определение того, что делает, а что не составляет дополнительных интеллектуальных усилий для понимания некоторого кода, довольно субъективно!
LJS
«var никогда не должен использоваться, за исключением случаев, когда тип неизвестен ...» - вы ВСЕГДА можете знать тип, как и компилятор. Это не динамическая типизация, это просто позволяет компилятору определить тип для вас. Но тип никогда не бывает неизвестным.
Габриэль Магана
5

Я раскол вар во всем места, только сомнительные места для меня являются внутренними короткими типами, например , я предпочитаю int i = 3;болееvar i = 3;

Роби-й
источник
5

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

var content  = new Queue<Pair<Regex, Func<string, bool>>>();
...
foreach (var entry in content) { ... }

Это было бы чрезвычайно многословно без var.

Приложение: Небольшое время, проведенное с языком с реальным выводом типа (например, F #), покажет, насколько хороши компиляторы для получения правильного типа выражений. Это определенно означало, что я склонен использовать varстолько, сколько я могу, и использование явного типа теперь указывает на то, что переменная не относится к типу инициализирующего выражения.

Ричард
источник
Да, компиляторы умнее нас, прекратите это!
Бенджол