Моменталізація нульових об'єктів за допомогою оператора Null-Coalescing


12

Розглянемо наступний типовий сценарій:

if(myObject == null) {
    myObject = new myClass();
}

Мені цікаво, що думає про наступну заміну за допомогою оператора зведення нуля:

myObject = myObject ?? new myClass();

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

Це розумна справа, чи є краща стенограма, яку я пропускаю? А може, "Це три рядки, здолайте!"?

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

myClass myObject = myClassService.getById(id);
myObject.myChildObject = myObject.myChildObject ?? new myChildClass();

15
Новачки вважають, що подібні речі є "хакітськими", більш досвідчені дияволи просто називають це "ідіоматичним".
Док Браун

Якщо об'єкт виглядає як об'єкт значення ("має значення семантики", в ідіоматичному мовленні), MyClassповинен надати public static readonlyчлену Emptyзначення свого типу. Дивіться String.Emptyна MSDN .
rwong


5
Немає ??=оператора?
aviv

1
@aviv Я б хотів, щоб було!
Лорен Печтел

Відповіді:


16

Я весь час використовую оператор нульового згортання. Мені подобається стислість цього.

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

Також ситуація, яку ви описуєте, - це лише один сценарій, коли оператор корисний. Також зручно замінити такі конструкції:

if (value != null)
{
    return value;
}
else
{ 
    return otherValue;
}

або

return value != null ? value : otherValue;

з

return value ?? otherValue;

Однозначно погоджуйтеся загалом щодо використання цього оператора. Коли я бачу посилання на його використання, це, як правило, щось подібне myObject = myObject2 ?? myObject3. Що конкретно мені цікаво, це використання оператора для встановлення об'єкта для себе, якщо це недійсне значення.
grin0048

2
Думаю, те саме міркування застосовується в будь-якому випадку. Це більш стислий спосіб висловити ту саму логіку.
17 з 26

Я пам’ятаю, що раз дивився на ІЛ для кожної з цих трьох форм. Перший та другий були однаковими, але третій був оптимізований так, як можна було вважати, nullпорівнянням.
Jesse C. Slicer

2

Що конкретно мені цікаво, це використання оператора для встановлення об'єкта для себе, якщо це недійсне значення.

Оператор ?? operatorназивається оператором узгодження нуля і використовується для визначення значення за замовчуванням для типів зведених значень або типів посилань. Він повертає лівий операнд, якщо операнд не є нульовим; інакше він повертає правильний операнд.

myObject = myObject ?? new myObject(); - instantiate default value of object

Більш детальна інформація та зразок коду про оператор нульового злиття - стаття MSDN .

Якщо ви перевірите more than nullableстан, в якості альтернативи ви можете скористатися оператором Ternary.

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

Ви також можете подивитися ?: Оператор . Його називають термінальним або умовним оператором. Умовний оператор (? :) повертає одне з двох значень залежно від значення булевого виразу.

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

Приклад коду від MSDN -?: Оператор (C # Reference) :

int? input = Convert.ToInt32(Console.ReadLine());
string classify;

// ?: conditional operator.
classify = (input.HasValue) ? ((input < 0) ? "negative" : "positive") : "undefined";

Отже, беручи приклад із запитання та застосовуючи умовний оператор, ми мали б щось подібне myObject = (myObject == null) ? new myClass() : myObject. Отже, якщо я не пропускаю кращого використання умовного оператора, він, мабуть, має ту саму "проблему" з встановленням об'єкта для себе (якщо він не є нульовим), як і оператор, що поєднує нуль, - і це менш стисло.
grin0048

Якщо ви перевіряєте на більш ніж одну умову (Не нульова та більша від нуля) - це зробить умовний оператор. Однак просто перевірка нуля працювала б ?? оператор.
Юсубов

2

Я не думаю, що такий сценарій є (або принаймні повинен бути) типовим.

Якщо ви хочете, щоб значення поля за замовчуванням не було null, то встановіть його в ініціалізаторі полів:

myClass myObject = new myClass();

Або, якщо ініціалізація є більш складною, встановіть її в конструкторі.

Якщо ви хочете створити myClassлише тоді, коли це фактично вам потрібно (наприклад, тому, що його створення займає багато часу), ви можете використовувати Lazy<T>:

Lazy<myClass> myObject = new Lazy<myClass>();

(Це викликає конструктор за замовчуванням. Якщо ініціалізація більш ускладнюється, передати лямбда , що створює myClassв Lazy<T>конструкторі.)

Щоб отримати доступ до значення, використовуйте myObject.Value, що викликає ініціалізацію, якщо ви вперше отримуєте доступ myObject.Value.


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

@ratchetfreak Так, саме тому я запропонував спочатку ініціалізатор поля.
svick

Є й інші випадки. На що я зараз дивлюся: Перший пропуск встановлює випадки виключення. Другий пропуск встановлює значення за замовчуванням для всього іншого. ?? = розрізав би лінію навпіл.
Лорен Печтел

1

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

public void DoSomething (MyClass thing1 = null) {
    thing1 = thing1 ?? new MyClass();
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.