Використання 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 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) {// ...} equivilent.

Тут існує справжня стурбованість щодо безпеки типу - наприклад, якщо ми розмістимо результати цього запиту в перевантажений метод, який прийняв IEnumerable <int> та IEnumerable <double>, що абонент може ненавмисно перейти у неправильний тип.

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


68
Використання var нормально, але "мені не потрібно з'ясовувати тип", це здається дуже поганою причиною його використання ... ти повинен знати, що таке тип, var - це лише ярлик, щоб уникнути його введення.
Томас Левеск

53
var i = 0;== провал! var c = new CrazyFrigginLongClassName();== виграй!
dotjoe

6
"Var також нагадує мені тип варіанту VB / VBA. Він також мав своє місце. Я пам'ятаю (з багатьох років тому) його використання було менш бажаним, і він був досить зголоднів". <- показує, що це питання приманки, оскільки тип "var" C # не має нічого спільного з типом варіанту VB / VBA.
user7116

20
var readabilityBeDamned = true;
подружжя

9
Проблема з усіма наведеними тут прикладами полягає в тому, що ми дивимось на один рядок коду. Коли я бачу рядок за рядком оголошень "var", одна за одною, це виходить з-під руки. Читання є суб'єктивним, але я вважаю, що вар зловживається набагато більше, ніж респектабельно.
jro

Відповіді:


293

Я все ще думаю, що varможе зробити код читабельнішим у деяких випадках. Якщо у мене є клас клієнта із властивістю Orders, і я хочу призначити його змінної, я просто зроблю це:

var orders = cust.Orders;

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

Порівняйте вищезгадану декларацію з:

ObservableCollection<Order> orders = cust.Orders;

Для мене назва типу - це просто шум. І якщо я повернусь назад і вирішу змінити тип клієнта. Надішліть доріжку (скажімо з ObservableCollection<Order>до IList<Order>), тоді мені теж потрібно змінити цю декларацію - те, чого я б не мав робити, якби я використовував var у першому місце.


48
Мені подобається мати явний тип перед собою, коли я читаю код. Як я можу знати, що тут "cust.Orders" без типу? Так, я можу навести курсор миші, щоб дізнатися це, але навіщо мені це робити? :)
Джон Таккабері

77
Але справа в тому, що в цілому це не має значення. Надані cust.Orders - це те, що ви можете перерахувати (наприклад, передбачити більше), то не важливо, для якого типу це. Додатковий код просто заважає читати наміри.
Метт Гамільтон

67
Але якщо ви вимагаєте лише від того, що cust.Orders є "чимось, що ви можете перерахувати", чи не декларує це як IEnumerable <Order>, зробіть цю вимогу явною і зрозумілою? Оголосивши це var, ви фактично втрачаєте цю вимогу.
GrahamS

5
@jon і як би IEnumerbal замовлення = cust.Orders foreach (var order in order) змінили? Єдине, що IEnumerable говорить, це те, що ви можете покласти це на передній план, але ви вже знали, що з рядка нижче
Rune FS

18
"Єдине, що IEnumerable говорить, - це ви можете поставити перед собою", - це також виражає намір, що єдине, що ви можете зробити, - це перерахувати. Використання var надає доступ до публічних членів конкретного типу збору та їх інтелігенції.
Джо

167

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

Справді, це може означати, що не ясно, з яким типом ми маємо справу. І що? Це фактично сенс розв'язаної конструкції. Маючи справу з інтерфейсами, ви напевно не зацікавлені у типі змінної. varприймає це набагато далі, правда, але я думаю , що цей аргумент залишається тим же самим з точки зору читання: Програміст не повинен фактично бути зацікавлені в типі змінної, а в тому, що змінна робить . Ось чому Microsoft також називає умовивід «типом качки».

Отже, що робить змінна, коли я декларую її за допомогою var? Легко, він робить все, що мені каже IntelliSense. Будь-які міркування щодо C #, що ігнорує IDE, не відповідають дійсності. На практиці кожен код C # запрограмований в IDE, який підтримує IntelliSense.

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

Тепер команда C # випустила керівництво з кодування, в якому йдеться про те, що його varслід використовувати лише для отримання результату оператора LINQ, який створює анонімний тип (адже тут у нас немає реальної альтернативи var). Ну, викрутіть це. Поки команда C # не надає мені вагомих аргументів для цієї настанови, я збираюся її ігнорувати, оскільки, на мою професійну та особисту думку, це чиста куля. (Вибачте; я не маю посилання на відповідний настанов.)

Насправді, є кілька (поверхово) хороших пояснень того, чому не слід користуватися, varале я все-таки вважаю, що вони значною мірою неправильні. Візьмемо для прикладу "searchchabililty": автор стверджує, що varускладнює пошук місць, де MyTypeвикористовується. Правильно. Так само робити інтерфейси. Власне, чому я хотів би знати, де використовується клас? Мені може бути цікавіше, де він створений, і це все одно буде шукати, оскільки десь його конструктор повинен викликати (навіть якщо це робиться побічно, ім'я типу потрібно десь згадувати).


14
У будь-якому пристойному IDE ви не використовуєте текстовий пошук для отримання класового використання, ви отримуєте IDE для цього на основі дерева розбору або в іншому випадку він визначає типи об'єктів. Оскільки ми говоримо про статичне введення тексту, це знайде все, крім анонімних типів.
Дастман

6
Мені б не хотілося успадковувати 100k рядків джерела без документації та ліберального використання var. Особливо, якщо ви поєднуєте var з менш корисними іменами змінних. Я можу вважати, що це корисно при ілюструванні пункту (або стосується анонімних типів), але у виробничому коді?
Ши

7
Арншея: добре, ви вже вказували на справжню проблему: непотрібні назви змінних та відсутність документації . Я дійсно не бачу, що varсприяє плутанині. Звичайно, можуть бути випадки, коли важливо підкреслити тип / розмір змінної (наприклад, бітові операції низького рівня). Це добре: ніхто ніколи не стверджував, що його varслід використовувати виключно. Правило просте: якщо це дійсно викликає плутанину, не використовуйте його.
Конрад Рудольф

17
Кожен приклад, протилежний var, який я бачив, передбачає, що програміст буде використовувати безглузді імена змінних. Але, можливо, саме тому var краще, ніж чітко вказати тип: Це змушує програміста придумувати хороші імена змінних.
Райан Лунді

16
Microsoft також називає висновок типу «набір качок». - вони справді? Я був би шокований ...
Антон Тихий

118

Var, на мою думку, в C # - це гарна річ tm . Будь-яка така введена змінна все ще сильно набрана, але вона отримує свій тип з правої частини завдання, де вона визначена. Оскільки інформація про тип доступна в правій частині, в більшості випадків зайве і надмірно багатослівне також потрібно вводити її зліва. Я думаю, що це значно збільшує читабельність, не знижуючи безпеку типу.

З моєї точки зору, використання хороших умов іменування змінних та методів важливіше з точки зору читабельності, ніж явна інформація про тип. Якщо мені потрібна інформація про тип, я завжди можу навести курсор на змінну (в VS) і отримати її. Однак, як правило, чітка інформація про тип читача не повинна бути необхідною. Для розробника в VS ви все ще отримуєте Intellisense, незалежно від того, як оголошена змінна. Сказавши все це, все ще можуть бути випадки, коли має сенс чітко оголосити тип - можливо, у вас є метод, який повертає a List<T>, але ви хочете трактувати це якIEnumerable<T>у вашому методі. Щоб переконатися, що ви використовуєте інтерфейс, декларування змінної типу інтерфейсу може зробити це явним. Або, можливо, ви хочете оголосити змінну без початкового значення - тому що вона одразу отримує значення на основі якоїсь умови. У такому випадку вам потрібен тип. Якщо інформація про тип є корисною або необхідною, продовжуйте використовувати її. Я вважаю, що зазвичай це не потрібно, і код легше читати без нього в більшості випадків.


3
Я згоден у цілому. На мою думку, ключовим моментом є впевненість у тому, що наміри зрозумілі. Якщо це не зрозуміло для більшості розробників у команді, то це згубно, а не корисно. Це сказало, що я особисто є ВЕЛИЧЕЗНИМ прихильником цього, але мені довелося трохи стримуватися, коли інші дияволи в моїй команді мали проблеми з визначенням моїх намірів. Піди розберися.
Стів Бройллард

3
Е, мені легше читати, коли тип ліворуч. Використовуючи ReSharper, мені не доведеться повторно вводити тип праворуч, тому це не турбує мене.
BlueRaja - Danny Pflughoeft

1
@BlueRaja - Я вважаю, що використання добрих імен змінних зазвичай взагалі виключає потребу розуміння фактичного типу. Intellisense все ще доступний для визначених "var" змінних, тому мені не потрібно знати тип, щоб вибрати метод / властивість на ньому при кодуванні.
tvanfosson

2
Справа не стільки в тому, коли ви кодуєте, скільки в тому, коли ви повинні прочитати код.
BlueRaja - Danny Pflughoeft

1
Тоді я просто повинен бути на товстій стороні, мені потрібні хороші назви методів та змінних та розуміння типів, якими керують, щоб мати можливість правильно зрозуміти код, який я читаю. Я думаю, ти маєш рацію, хоча це симптом більшої проблеми. Один з довіри. Щоб бути впевненим, що код виконує те, що, схоже, робить, вам потрібно бути впевненим у використанні типів.
AnthonyWJones

91

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

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

varне впливає на продуктивність, оскільки це синтаксичний цукор; компілятор визначає тип і визначає його, як тільки він компілюється в IL; насправді в цьому немає нічого динамічного.


1
погодьтеся про обидва, хоча у мене є довгі обмеження щодо другого випадку, якщо тип такий довгий, зазвичай це загальний тип з великою кількістю вкладених загальних аргументів, у цьому випадку сильно набраний "ShortType еквівалент типу TypeWithAReallyLongNameTheresNoSenseRepeating" має більше сенсу
Іон Тодірел

12
У мене немає бажання починати релігійну війну, але я особисто схильний не погоджуватися з Іоном. Я б більше віддав перевагу дуже довге, але дуже точне ім’я типу (аля дядько Боб Мартін), ніж скорочене і, можливо, неоднозначне коротше ім’я типу. Я додам застереження, з яким я НЕ погоджуюся штучно завищувати довжину імені. Якщо 5 символів створюють лаконічне ім’я, яке чітко показує наміри, тоді використовуйте 5, а не 25.
Стів Бройллард

2
@Steve: я повинен погодитися з тобою; створення "короткого типу" (який, мабуть, ви маєте на увазі як успадкування від конкретного родового типу виключно з метою скорочення назви), не є хорошою практикою; це зажадає від вас дублювання та проходження будь-яких конструкторів із загального типу, а також не дозволяє вам передавати інший тип, який успадковується від загального типу до функції. Ви використовуєте спадщину, як 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.


Я вважаю аргумент Ліпперта дивним. Ніхто не вводить ім'я другого класу, вони дозволяють Intellisense написати це для них, але потім він обертається і стверджує, що var краще, тому що компілятор / Intellisense це працює. Не можна мати це обома способами!
Дейв

5
Команда C # не контролює інтелігенцію, вони керують компілятором. У будь-якому випадку це не головне питання. Я не думаю, що var би набрав 100 балів за заощадження набору тексту.
Дастман

@Dustman: var взагалі не економить набравши текст. Це змушує писати більше!
Пьотр Перак

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) використовую var.


6
Ну єдине, що не так з "var f = (float) 3;" полягає в тому, що він повинен бути "var f = 3f" або "var f = 3.0 (спричиняє одноточний відстій)".
MichaelGG

3
Хе да 3f або 3.0 - це шлях! Нам вар маніякам доводиться злипатися!
Метт Гамільтон

27
Справжня проблема в цьому першому прикладі - "список", а не "с". "список" чого ? "список" повинен бути перейменований на "замовники", або "замовникиWhoOweMoney", або "поточні клієнти", або щось набагато більш описовий. І як тільки ви це зробите, "c" може залишитися таким, яким є, тому що ви вже знаєте, що воно буде містити.
Райан Лунді

4
Привіт Метт! Мене звуть Кенні, і я судья.
kenny

var MattHamil = "Люк Скайуокер"; // позбавив тонну з неї
Біной Антоній

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

«Код для людей, а не машин» - амінь.
користувач1068352

39

Це непогано, це більше стилістична річ, яка має тенденцію бути суб’єктивною. Це може додавати невідповідності, коли ви використовуєте var і коли ви цього не робите.

Інший випадок, який викликає занепокоєння, у наступному дзвінку ви не можете сказати, просто подивившись на код, який повертає CallMe:

var variable = CallMe();

Ось моя головна скарга на вар.

Я використовую var, коли в методах оголошую анонімних делегатів, інакше var виглядає чистіше, ніж якби я використовував Func. Розглянемо цей код:

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

EDIT : Оновлено останній зразок коду на основі даних Джуліана


3
Але чи справді вам потрібно знати тип саме на цій лінії? Ви знаєте, що CallMe щось повертає; Чи недостатньо знати, що створена локальна змінна з назвою variable? Якщо ви не розгорнете свій приклад, це не дуже солідна скарга, IMO.
Рендольфо

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% потрібно); але це також уникає повторення тривіальних випадків, і ІМО робить лінію чіткішою. Мені не потрібно бачити тип двічі для простої ініціалізації.

Наприклад:

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

(будь ласка, не редагуйте hscroll у зазначеному вище - це ніби доводить суть !!!)

vs:

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);

1
(для інформації, ви можете отримати подібні проблеми з усього, де це неявна конверсія типу)
Marc Gravell

1
Не погоджуйтеся з тією частиною, що ви не хочете бачити її двічі в одному рядку. Цілком можливо, що в майбутньому ви не будете безпосередньо створювати змінну після оголошення (наприклад, у випадку if нижче визначення), ніж це може бути не зрозуміло, що це за тип. Більшість розробників звикли бачити тип безпосередньо на початку рядка, особливо у складному коді, який не хочеться ускладнювати читання коду.
Гертьян

@TheVillageIdiot - я відмовив вашу редагування, тому що з цього приводу hscroll пов'язаний з точкою
;-p

2
@Gertjan - мій мозок обмежений; якщо він складний, я не хочу його бачити двічі і треба починати зіставляти (інтерфейс / конкретні / тощо). Я радий бачити це один раз і думаю, що "набрав як один з них".
Марк Гравелл

17

Один конкретний випадок, коли вар важкий: перегляд офлайн-коду, особливо тих, що зроблені на папері.

Для цього ви не можете покластися на перемикання миші.


17
Чому чорт ви переглядаєте код на папері? Подумайте про дерева! ;)
Дастман

8
Ви можете мати ту саму проблему, не використовуючи var. Проблема не вар; проблема в поганих назвах змінних. Якщо імена змінних правильно вибрані, використання var не має значення.
Райан Лунді

У моїй команді є хлопець, який переглядає власний код і шукає помилки, друкуючи його код. Його стіни ПОКРІТІ кодом. Я одного разу зайшов, і у нього була ціла велика дошка, покрита однією з його вправ налагодження. Ймовірно, це було ~ 10000 LOC
звуковий сигнал

Імена змінних самі по собі не вирішують проблему, якщо ви не повернетесь до угорської позначення, де тип є частиною імені.
Кевін Гейл

17

Я не бачу, у чому полягає велика справа ..

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

Ви все ще маєте повну інтелігенцію щодо "чогось", і для будь-якого неоднозначного випадку ви маєте свої одиничні тести, правда? ( чи ти? )

Це не варчар, він не тьмяний, і це, звичайно, не динамічний або слабкий набір тексту. Він зупиняє маддні так:

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

і зменшити цю загальну суть думок до:

var v = new List<somethinglongtypename>();

Приємно, не так добре, як:

v = List<somethinglongtypename>();

Але тоді це Бу .


тип "чогось" є зрозумілим для компілятора, внутрішньо "var" встановлюється на тип повернення "someMethod", він є зрозумілим для компілятора, але може бути не зрозумілим розробникам, які працюють над проектом. і Бу на мене швидко росте.
stephenbayer

Ні, v = List<somethinglongtypename>();навіть не приємніше. Важливо розрізняти введення нової змінної та присвоєння існуючій змінній.
HighCommander4

Добре, якщо ви раніше призначали 'v' у поточному діапазоні, то це присвоєння існуючому. В іншому випадку це призначення новій змінній 'v'. Легко.
Фреп Д-Оронж

17

Якщо хтось використовує varключове слово, оскільки він не хоче "з'ясувати тип", це, безумовно, неправильна причина. ThevarКлючове слово не створює змінну з типом динамічного, компілятор все одно повинен знати тип. Оскільки змінна завжди має певний тип, тип також має бути очевидним у коді, якщо це можливо.

Вагомі причини для використання varключового слова є, наприклад:

  • Там, де це потрібно, тобто оголосити посилання на анонімний тип.
  • Там, де він робить код більш читабельним, тобто видаляючи повторювані декларації.

Запис типу даних часто полегшує дотримання коду. Він показує, які типи даних ви використовуєте, так що вам не доведеться з'ясовувати тип даних, попередньо з’ясувавши, що робить код.


11

З огляду на те, наскільки потужний Intellisense зараз, я не впевнений, що var важче прочитати, ніж мати змінні учасники в класі або локальні змінні у методі, визначеному за межами видимої області екрана.

Якщо у вас є рядок коду, такий як

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

Читати набагато простіше чи складніше, ніж:

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

Я насправді не вважав це, але, як видається, з іншого питання це досить вагомий момент для його використання.
Finglas

Це в основному була єдиною причиною їх реалізації (крім того, що вони могли оголосити анонімні типи, але вони могли зробити "var" спеціальним ключовим словом, призначеним лише для анонімних типів.)
mqp

10

Я думаю, що ключовим з VAR є використання його лише там, де це доречно, тобто, коли це робиться в Linq, що це полегшує (і, мабуть, в інших випадках).

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

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

Інша річ , щоб пам'ятати про те , що його не тип VB вар в тому , що він не може змінити тип - це є строго типізований змінним його тільки що тип виводяться (тому є люди , які будуть стверджувати , що його не нерозумно використовувати його, скажімо, в передбаченні, але я не погоджуюся з причин як читабельності, так і ремонтопридатності).

Я підозрюю, що цей збирається бігати і бігати (-:

Мерф


10

Звичайно, intце просто, але коли тип змінної є IEnumerable<MyStupidLongNamedGenericClass<int, string>>, var робить все набагато простішим.


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());
...

замість цього вам не потрібно змінювати.


погодився - цікаво, чому цей приємний побічний ефект не рекламується так само, як деякі інші, більш суб'єктивні плюси в більш популярних відповідях.
fieldingmellish

Сьогодні у мене це трапляється. У мене є заводський клас, який повертає значення класу MainMenu. Сьогодні я створив MainMenu2 з тим же інтерфейсом MainMenu. У мене весь код програми не змінився після зміни!
Marco Staffoli

8

@aku: Одним із прикладів є огляди коду. Інший приклад - сценарії рефакторингу.

В основному, я не хочу ходити на миші на полювання за допомогою миші. Він може бути недоступним.


2
Цікаво, що ви кажете, що тому що var може спростити рефакторинг. Якщо ви використовували var, вам цього не потрібно. Тепер ви завжди можете покластися на інструменти рефакторингу IDE, але знаєте, ви завжди можете покластись на IDE і для типу :)
Фред

8

Це питання смаку. Вся ця метушня щодо типу змінної зникає, коли ти звикаєш до динамічно набраних мов. Тобто, якщо вам коли-небудь почнуть подобатися (я не впевнений, чи можуть всі, але я це роблю).

C # 's varдосить крутий тим, що виглядає як динамічне введення тексту, але насправді це статичне введення тексту - компілятор застосовує правильне використання.

Тип вашої змінної насправді не так важливий (про це було сказано раніше). Це повинно бути відносно зрозумілим з контексту (його взаємодії з іншими змінними та методами) та його назви - не сподівайтеся, що список клієнтів містить 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 # досить розумний - типи, що генеруються окремо, будуть мати однаковий тип, якщо їх властивості збігаються.

Поза межами цього, доки ви маєте інтелігенцію, має сенс використовувати 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

насправді з цим було неможливо мати справу, ніхто не використовував динамічно набрані мови.


Імовірно, у .Net 4, де динамічні типи є загальним місцем, це стане важливішим?
Колін Десмонд

2
Навпаки, якщо зараз вас бентежить "вар", я б очікував, що вас додатково збентежить "динамічний". Не дай Бог, щоб хто-небудь декларував динаміку, а потім
робив

Я мав на увазі щось на зразок динамічного 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;

(тому що компілятор не може знати, чи хочу я байт, короткий, 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. Мій антагонізм до ключового слова var випливає безпосередньо з мого володіння JavaScript! :)
уріг

varу C # не має жодного зв'язку з varJavaScript. var-Declared змінної в C # сильно типізованих.
Райан Лунді

6

Використовуйте його для анонімних типів - саме для цього і є. Все інше - це використання занадто далеко. Як і багато людей, які виросли на C, я звик дивитись ліворуч від декларації для типу. Я не дивлюся на правий бік, якщо не треба. Використання varдля будь-якої старої декларації змушує мене робити це постійно, що мені особисто незручно.

Ті, хто каже: "Неважливо, використовуй те, чим ти задоволений", не бачать усієї картини. Кожен підбирає код інших людей в той чи інший момент і повинен мати справу з будь-якими рішеннями, які вони приймали на момент написання. Досить погано мати справу з радикально різними умовами іменування, або - класичним стисканням - зміцнюючих стилів, не додаючи varв суміш цілу річ " чи ні". Найгірший випадок, коли один програміст не користувавсяvar а потім приходить обслуговуючий, який його любить, і розширює код, використовуючи його. Тож тепер у вас неприємний безлад.

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

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


7
Ого. Ігнорування всіх аргументів, викладених у цій темі дотепер, та повторне налаштування всієї дискусії є цілим досягненням.
Конрад Рудольф

Це 100% описує, як я ставлюсь до "var", особливо з точки зору вибору коду "elses". Використання 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;

Без вар, мені доведеться продовжувати змінювати заявлений тип і на лівій стороні. Я знаю, що це другорядне, але це надзвичайно зручно.


6

Для прихильників, які думають, що varекономить час, потрібно набрати менше натискань клавіш:

StringBuilder sb = new StringBuilder();

ніж

var sb = new StringBuilder();

Порахуй їх, якщо ти мені не повіриш ...

19 проти 21

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

І це правда для кожного типу, про який ви можете придумати !!

Моє особисте відчуття полягає в тому, що var ніколи не слід використовувати, за винятком випадків, коли тип не відомий, оскільки він зменшує розпізнавання читабельності в коді. Мозку потрібно довше, щоб розпізнати тип, ніж повна лінія. Старі таймери, які розуміють машинний код і біти, точно знають, про що я говорю. Мозок працює паралельно, і коли ви використовуєте var, ви змушуєте його серіалізувати свій внесок. Чому хтось хотів би зробити так, щоб їхній мозок працював важче? Саме для цього потрібні комп'ютери.


Я вважаю повторення 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стільки, скільки можу, і використання явного типу тепер вказує на те, що змінна не є типом виразу, що ініціалізує.


Так, компілятори розумніші за нас, здолайте це!
Бенжол

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.