Наскільки далеко повинен працювати "var" і нульовий оператор злиття "??" розважатись, не перешкоджаючи читанню?


23

Я знаю, що заголовок питання дуже суб'єктивний, але я зіткнувся з використанням ??оператора моїми однолітками, де в той же час я був не дуже задоволений / комфортний із застосуванням varнового нового коду.

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

Моє запитання: чи не відбувається те ж саме, коли ви починаєте використовувати var?


49
Якщо "розробник" не може зрозуміти ??оператора "null coalesce" після його пояснення, він не повинен бути дозволений поблизу виробничого коду.
CaffGeek

12
Я пропоную змінити оператора з ?? до IfNullThen. ? може бути IfSoChoose,: є ElseChoose. + - Додати. - віднімання, якщо воно не є однорідним, то це негатив. - розділений між DecrementBeforeUsing та DecrementAfterUsing. У C ++ ви можете це зробити за допомогою макросів.
Лі Лув'є

7
@Xaade: Це іронія, чи не так? ... правда? ... Бог нехай це буде іронія (а я атеїст).
Стівен Євріс

10
@StevenJeuris Це може бути сарказм , але це не іронія .
Кірк Бродхерст

1
@KirkBroadhurst: Я поправляюся , завжди плутаю це двоє.
Стівен Євріс

Відповіді:


53

Нульовий оператор злиття (??)

Особисто я не бачу жодних недоліків використання цього оператора. Розглянемо наступні три зразки коду, від «легких» до «складних» нових операторів.

Без магії:

bool isNameSet = false;
string name;
if ( isNameSet )
{
    Console.WriteLine( name );
}
else
{
    Console.WriteLine( "No name set." );
}

Термінальний оператор:

bool isNameSet = false;
string name;
Console.WriteLine( isNameSet ? name : "No name set." );

Нульове згортання:

string name = null;
Console.WriteLine( name ?? "No name set." );

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

var ключове слово

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

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

  • Переважно в циклах foreach , про які я дізнався від Resharper, оскільки це налаштування там. Здебільшого ви знаєте, який тип колекції ви проїжджаєте, тому знаєте, що очікуєте предметів із цієї колекції.
  • Запитання Linq . Результатом запитів linq часто є дуже складні загальні типи. Показ цього типу приносить більше шкоди, ніж користі.
  • Довгі назви, які просто ініціалізуються з їх конструктором. Ви вже можете сказати, що таке тип, подивившись на конструктор.

Як приклад останнього твердження:

ThisIsSomeSpecializedTypeRightHere duplication =
    new ThisIsSomeSpecializedTypeRightHere();
var justAsReadable =
    new ThisIsSomeSpecializedTypeRightHere();  // Less duplication.

// But I still prefer the following ...
int number = 9;
SomeCreatedType foo = Factory.CreateSomeType();

24
Цей останній приклад - це саме те, коли ключове слово var може перевершуватися. Уявіть, що код зафіксований у вашому коді. Factory.CreateSomeTypeповертає IEnumerable<SomeType>. Одного разу з будь-якої причини він змінюється, щоб повернутися SomeType[]. Якщо ви використовували var, це просто перекомпіляція.
пдр

1
Зробив цей приклад неправильно, а потім пішов шукати їжу. Чисто! Кращим прикладом може бути використання вашого. Що робити, якщо Factory.CreateSomeType()зміни повернути ISomeType?
пдр

4
@pdr: Це, швидше за все, означає, що інтерфейс також змінився, і поведінку потрібно також коригувати / додавати. Якщо це просто перейменування, ви, звичайно, маєте автоматичне перейменування. Якщо "контракт" змінюється, я швидше бачу, як мій код порушується, щоб я міг щось коригувати чи ні.
Стівен Євріс

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

1
@Tom Hawtin, ми всі знаємо, що неминуче уникати nullцілком. Крім того, чим більше я шукаю альтернативи null, тим більше я усвідомлюю null, що іноді використовується найчистіше рішення. Мій наведений приклад не все так погано IMHO, і я вважаю це відповідним використанням змінних типів.
Стівен Євріс

16

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

...
foreach (var message in messages) {
  var label = Factory.CreateLabel();
  label.Text = message;
  Controls.Add(label);
}
...

Кого хвилює, який тип мітки, якщо він надає властивість Text?


Хтось намагається зрозуміти, це, наприклад, етикетка winforms або WPF.
Стівен Євріс

14
@Steven Jeuris: зазвичай це відома інформація про контекст. Якщо ні, то ви підходите до коду неправильно.
Кодизм

Хтось, хто хоче знати, чи це ярлик WPF за замовчуванням, чи інша спеціальна мітка? :)
Стівен Євріс

14
1. Чи повинен ця людина насправді дбати, якщо це мітка із властивістю Text? 2. Якщо це один із рідкісних випадків, коли вони дійсно мають вагомий привід для турботи, попросіть Інтеллісенса. 3. Якщо вони редагування коду в IDE без Intellisense, вони , ймовірно, шлях більше незручностей , ніж «вар» :)
KutuluMike

4
Хтось із поганим почуттям абстракції.
Джим Балтер

16

У мене немає жодних серйозних коментарів до ??оператора, оскільки я ніколи не використовував мови з таким оператором сильно. Щодо того var, люди програмують на таких мовах як Ruby, Python, Perl та PHP, які весь час неявно вводять текст. Уродженці цих мов розуміють, що формальний тип змінної, як правило, не має значення. Вас більше цікавить, що може робити змінна , тобто її структурний / дак-інтерфейс.

Аналогічно, я програмую в основному на D. D введений статично, але має autoключове слово, яке еквівалентно var. Ідіоматичним вважається використовувати його скрізь, якщо ви не бачите конкретної необхідності підкреслювати тип чого-небудь читачеві чи (через неявне перетворення) компілятору. За винятком випадків, коли використовується як тип повернення функції (це дозволено в D), я ніколи не вважав, що це перешкоджає читанню, тому що я, головним чином, думаю, що стосується структурних / дак-інтерфейсів, а не формальних / номінативних типів, коли я програмую.

Крім того, ІМХО, що використовує varвсюди можливий, є хорошим прикладом сухих. Тип чогось слід вказати в одному і лише одному місці, а потім автоматично поширювати, коли це потрібно розмножувати. Якщо ви використовуєте varі формальний тип змінної потрібно змінити в якийсь момент, необхідні зміни автоматично розповсюджуються скрізь, де це потрібно компілятором, доки програма все ще не відповідає правилам типу, а не програмісту, який повинен вручну змінювати кожен екземпляр . Це гарна річ (TM).


13

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

Однак якщо я працюю один, то знаходжу ?? і Var чітко читається без обмежень. Навіть

var a = b ?? c ?? d ?? e ?? "";

для мене досить однозначно.

Тернальні оператори і dynamic, звичайно, інша справа.


4
Я б тут використав `String.Empty '.
Робота

1
@Job, чесно, так би і я. Я збирався щось поставити в цю струну, тоді нічого не міг придумати :)
pdr

4
var a = b ?? c ?? d ?? e ?? String.Empty ?? "";
Лі Лув'є

2
@Xaade Ви ніколи не можете бути досить впевненими. Але насправді використання String.Empty або "" - це особисті переваги. Я використовую "", тому що це коротше ...
Carra

12
@Xaade - якщо String.Emptyколи-небудь повернеться null, ми чекаємо на пекло багато зламаного коду.
Jesse C. Slicer

10

Аргумент, наведений для використання ?? Оператор був, він забирає читабельність у коді.

Коротко подумавши про це, цей коментар повідомляє мені людину, яка коментує, не розуміє її так добре, як вона / вона повинна. Це, швидше за все, правда в певних ситуаціях, але в цілому я не знижую те, що команда C #, очевидно, вважала достатньо важливою для додавання через "читабельність". Я поклав це в тій же категорії if(boolean_object)проти if(boolean_object == true). Деякі люди стверджують, що друге читабельніше, але насправді це просто додавання додаткового коду для того, щоб хтось читав / набирав текст, а в деяких ситуаціях може бути більш заплутаним (подумайте if(boolean_object != false))

Моє запитання: чи не відбувається те ж саме, коли ви починаєте використовувати var?

Команда C # дозволила вам не визначати те, що ви знаєте, що це буде. Якщо мені абсолютно не потрібно визначити, що буде змінною (або це абсолютно важливо, щоб об'єкт, що повертається, був тип x, або він справді не читається), я використовую var. var x = "MY_STRING";Я знаю, що це струна від погляду на це. По правді кажучи, мені дуже не байдуже, що це струна, доки вона робить те, що мені потрібно для цього. Визначення типу змінної є моєю користю, а не компілятором. Якщо щось не так, компілятор скаже мені, коли він працює, якщо я маю неправильний тип змінної.


0

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

Однак робити var text = "Some text " + variableName + "some more text."це просто лінь.

EDIT: @Jorg Ви спеціально спрощено відповіли, але нічого не додали до дискусії. Добре, як щодо цього для кращого прикладу: var items = doc.DocumentElement.FirstChild.ChildNodes;Якщо ви зможете розібратися з типом, я дам вам печиво.


18
Якщо ви не можете зрозуміти, що "Some text "це таке string, то у вас виникають набагато більші проблеми, ніж через кількість vars у вашому коді.
Йорг W Міттаг

3
Проблема не в цьому var; проблема полягає в шаленій назві змінної "items". Якщо ви використовуєте гарне ім'я змінної, нічого поганого в цьому немає var.
Kyralessa

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

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

1
"просто ледачий" - Це не аргумент проти цього. Насправді це зовсім не розумно.
Джим Балтер

0

У мене є принципова проблема використання var.

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

Врахуйте це:

public MyFirstObject GetMeAnObject() {
    return new MyFirstObject();
}

public void MainProgram() {
    var theObject = GetMeAnObject();
    theObject.PerformOperation();
}

Що станеться, якщо хтось інший змінить GetMeAnObject відповідно до їх потреб?

public MySecondObject GetMeAnObject() {
    return new MySecondObject();
}

Метод MainProgram матиме велику червону помилку при .PerformOperation (). Що сталося? Раніше PerformOperation працював на відмінно. Ми дивимося на методи на об'єкті, і він просто безслідно зник. Це був останній раз, і нам потрібен цей метод. Ви можете довго переслідувати хвіст і намагаючись з'ясувати, чому, якщо MyFirstObject має метод, який називається PerformOperation, його зараз не можна побачити. Усі "знають", що GetMeAnObject повертає MyFirstObject, тому немає сенсу перевіряти це.

Якби ви явно набрали theObject, у вас буде помилка Invalid Cast на лінії, яка викликає GetMeAnObject, і було б сліпуче очевидно, що GetMeAnObject повертає тип, який не є тим, що ви очікуєте.

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


10
Співробітник змінив код, який не охоплюється тестами, і ви вважаєте, що проблема var? Не можна очікувати, що мова захищатиме від такої поведінки - що робити, якщо вони змінили MyFirstObject безпосередньо? Він би все-таки зламався, але жоден синтаксис не міг би вас врятувати від цього. Я б вважав це сильним var, навіть: що якщо замість повернення MySecondObject ви зараз повертаєте IMyFirstObject?
Фоши

2
"Усі" знають ", що GetMeAnObject повертає MyFirstObject, тому немає сенсу перевіряти це." Я насправді не можу придумати сценарій програмування, де я б фактично залежав від своєї пам’яті про те, що GetMeAnObject, якщо я налагоджую. Якби я перевірив, що PerformOperation немає, я б побачив код, і ні, це не для іншого класу. Якщо в IDE клас з’явиться екземпляр, я дивлюся на тип об’єкта. Насправді, коли компілятор повідомляє мені про помилку, він би сказав "клас MySecondObject не має операції PerformOperation". Як це всім відомо?
Мухаммед Алкарурі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.