Дійшов до цього рядка коду:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
Що означають два знаки запитання, це якийсь потрійний оператор? Важко шукати в Google.
Дійшов до цього рядка коду:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
Що означають два знаки запитання, це якийсь потрійний оператор? Важко шукати в Google.
Відповіді:
Це нульовий оператор злиття, і дуже схожий на потрійний (негайний) оператор. Дивіться також ?? Оператор - MSDN .
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
розширюється до:
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();
яка далі розширюється до:
if(formsAuth != null)
FormsAuth = formsAuth;
else
FormsAuth = new FormsAuthenticationWrapper();
Англійською це означає "Якщо все, що знаходиться зліва, не є нульовим, використовуйте це, інакше використовуйте те, що праворуч".
Зауважте, що ви можете використовувати будь-яку кількість цих послідовностей. Наступний оператор привласнює перший ненульовими Answer#
до Answer
(якщо всі відповіді дорівнюють нулю , то Answer
дорівнює нулю):
string Answer = Answer1 ?? Answer2 ?? Answer3 ?? Answer4;
Також варто згадати, коли розширення вище є концептуально рівнозначним, результат кожного виразу оцінюється лише один раз. Це важливо, якщо, наприклад, вираз є викликом методу з побічними ефектами. (Подяку @Joey за вказівку на це.)
??
ліворуч асоціативний, тому a ?? b ?? c ?? d
еквівалентний ((a ?? b) ?? c ) ?? d
. "Оператори присвоєння та потрійний оператор (? :) є правими асоціативними. Усі інші бінарні оператори залишаються лівими асоціативними." Джерело: msdn.microsoft.com/en-us/library/ms173145.aspx
Просто тому, що ніхто ще не сказав магічних слів: це оператор з’єднання нуля . Це визначено в розділі 7.12 специфікації мови C # 3.0 .
Це дуже зручно, особливо через те, як він працює, коли його вживають кілька разів у виразі. Вираз форми:
a ?? b ?? c ?? d
дасть результат вираження, a
якщо він не є нульовим, інакше спробуйте b
, інакше спробуйте c
, інакше спробуйте d
. Це коротке замикання в кожній точці.
Також, якщо тип не d
є нульовим, тип цілого виразу також не зводиться до нуля.
Це нульовий оператор злиття.
http://msdn.microsoft.com/en-us/library/ms173224.aspx
Так, майже неможливо шукати, якщо ви не знаєте, як це називається! :-)
EDIT: І це класна особливість іншого питання. Ви можете зав'язати їх ланцюгом.
Дякую всім, ось найяскравіше пояснення, яке я знайшов на сайті MSDN:
// y = x, unless x is null, in which case y = -1.
int y = x ?? -1;
-1
це просто звичайна int
, яка не є нульовою).
x
є тип int?
, але y
має тип int
, ви можете написати int y = (int)(x ?? -1)
. Він буде розбирати x
Аня , int
якщо це не null
, або призначити -1
в y
разі x
це null
.
Два знаки запитання (??) вказують на те, що його оператор Coalescing.
Оператор злиття повертає перше значення NON-NULL з ланцюга. Ви можете побачити це відео на YouTube, яке практично демонструє все.
Але дозвольте додати більше до того, що йдеться у відео.
Якщо ви бачите англійське значення поєднання, воно говорить: "консолідуватись разом". Наприклад нижче - простий коалісцентний код, який ланцюжком містить чотири рядки.
Так що, якщо str1
це null
буде намагатися str2
, якщо str2
це null
буде намагатися str3
і так далі до тих пір , поки не знайде рядок зі значенням ненульовим.
string final = str1 ?? str2 ?? str3 ?? str4;
Простими словами оператор Coalescing повертає перше значення NON-NULL з ланцюга.
Це коротка рука для потрійного оператора.
FormsAuth = (formsAuth != null) ? formsAuth : new FormsAuthenticationWrapper();
Або для тих, хто не займається трійкою:
if (formsAuth != null)
{
FormsAuth = formsAuth;
}
else
{
FormsAuth = new FormsAuthenticationWrapper();
}
!= null
), і другий formsAuth
(після ?
) можуть бути змінені; у формі null coalesce обидва неявно приймають вказані вами значення.
Якщо ви знайомі з Рубі, це ||=
здається ??
мені схожим на C # . Ось деякі Ruby:
irb(main):001:0> str1 = nil
=> nil
irb(main):002:0> str1 ||= "new value"
=> "new value"
irb(main):003:0> str2 = "old value"
=> "old value"
irb(main):004:0> str2 ||= "another new value"
=> "old value"
irb(main):005:0> str1
=> "new value"
irb(main):006:0> str2
=> "old value"
І в C #:
string str1 = null;
str1 = str1 ?? "new value";
string str2 = "old value";
str2 = str2 ?? "another new value";
x ||= y
desugars на щось подібне x = x || y
, так ??
насправді більше схожий на звичайний ||
у Ruby.
??
тільки дбає про null
, в той час як ||
оператор в Ruby, як і в більшості мов, більше про null
, false
або що - небудь , що можна розглядати як логічне зі значенням false
(наприклад , в деяких мовах, ""
). Це не гарна чи погана річ, просто різниця.
Нічого небезпечного в цьому немає. Насправді це красиво. Ви можете додати значення за замовчуванням, якщо це бажано, наприклад:
КОД
int x = x1 ?? x2 ?? x3 ?? x4 ?? 0;
int? x1 = null;
Правильно
x1
- x4
повинен бути обнуляється типами: це не має ніякого сенсу говорити, по суті, «результат , 0
якщо x4
цього значення , яке воно не може прийняти» ( null
). "Нульовий тип" сюди включає , звичайно, і типи нульових значень, і референтні типи. Це помилка часу компіляції, якщо одна чи більше ланцюгових змінних (крім останньої) не зводиться до нуля.
Як правильно зазначається в численних відповідях, це "оператор зв'язання нуля" ( ?? ), говорячи про який, ви також можете перевірити його двоюрідного брата "Нульового умовного оператора" ( ?. Або ? [ ), Який є оператором, який багато разів він використовується спільно з ??
Використовується для тестування на null перед виконанням операції доступу члена ( ?. ) Або індексу ( ? [ ). Ці оператори допомагають вам писати менше коду для обробки нульових перевірок, особливо для спуску в структури даних.
Наприклад:
// if 'customers' or 'Order' property or 'Price' property is null,
// dollarAmount will be 0
// otherwise dollarAmount will be equal to 'customers.Order.Price'
int dollarAmount = customers?.Order?.Price ?? 0;
старий шлях без ?. і ?? робити це є
int dollarAmount = customers != null
&& customers.Order!=null
&& customers.Order.Price!=null
? customers.Order.Price : 0;
яка більш багатослівна і громіздка.
Для вашого розваги (знаючи, що ви всі C # хлопці ;-).
Я думаю, що вона виникла в Smalltalk, де вона існує вже багато років. Там він визначається як:
в Об'єкт:
? anArgument
^ self
у UndefinedObject (клас aka nil):
? anArgument
^ anArgument
Існують як оцінювальні (?), Так і неоцінювальні версії (??) цього.
Він часто зустрічається в методах getter для ліниво-ініціалізованих приватних змінних (екземпляр), які залишаються нульовими, поки дійсно не знадобляться.
Деякі з прикладів отримання значень за допомогою злиття неефективні.
Те, що ти насправді хочеш:
return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();
або
return _formsAuthWrapper ?? (_formsAuthWrapper = new FormsAuthenticationWrapper());
Це запобігає відновленню об'єкта кожного разу. Замість того, щоб приватна змінна залишалася нульовою та створювався новий об'єкт при кожному запиті, це забезпечує присвоєння приватної змінної, якщо новий об’єкт створений.
??
оцінюється ярлик? new FormsAuthenticationWrapper();
оцінюється, якщо і лише тоді, коли _formsAuthWrapper
нуль.
Я прочитав цілу нитку та багато інших, але не можу знайти такої ґрунтовної відповіді, як це.
За допомогою якого я повністю зрозумів "навіщо користуватися і коли використовувати та як користуватися".
Фонд комунікацій з Windows, розв'язаний Крейгом Макмюртрі ISBN 0-672-32948-4
Є дві загальні обставини, за яких хотілося б дізнатися, чи присвоєно значення екземпляру типу значення. Перший - це коли екземпляр представляє значення в базі даних. У такому випадку хотілося б мати можливість досліджувати екземпляр, щоб з’ясувати, чи є значення дійсно в базі даних. Інша обставина, яка більше стосується теми цієї книги, - це коли екземпляр представляє елемент даних, отриманий з якогось віддаленого джерела. Знову ж таки, хотілося б визначити з примірника, чи було отримано значення для цього елемента даних.
.NET Framework 2.0 включає в себе визначення загального типу, яке передбачає такі випадки, в яких хочеться призначити null екземпляру типу значення і перевірити, чи значення примірника є нульовим. Це загальне визначення типу - System.Nullable, що обмежує аргументи загального типу, які можуть бути замінені на T значеннями. Екземплярам типів, побудованих із System.Nullable, може бути призначене значення null; Дійсно, їх значення за замовчуванням є нульовими. Таким чином, типи, побудовані з System.Nullable, можуть називатися типами нульового значення. System.Nullable має властивість Value, за допомогою якої може бути отримане значення, присвоєне екземпляру типу, побудованого з нього, якщо значення екземпляра не є нульовим. Тому можна написати:
System.Nullable<int> myNullableInteger = null;
myNullableInteger = 1;
if (myNullableInteger != null)
{
Console.WriteLine(myNullableInteger.Value);
}
Мова програмування C # пропонує скорочений синтаксис для оголошення типів, побудованих із System.Nullable. Цей синтаксис дозволяє скоротити:
System.Nullable<int> myNullableInteger;
до
int? myNullableInteger;
Компілятор запобіжить спробі присвоїти значення типу нульового значення звичайному типу значення таким чином:
int? myNullableInteger = null;
int myInteger = myNullableInteger;
Це заважає робити це тому, що тип нульового значення може мати значення null, яке воно насправді було б у цьому випадку, і це значення не може бути присвоєно звичайному типу значення. Хоча компілятор дозволив би цей код,
int? myNullableInteger = null;
int myInteger = myNullableInteger.Value;
Другий оператор спричинить викид виключення, оскільки будь-яка спроба отримати доступ до властивості System.Nullable.Value є недійсною операцією, якщо типу, побудованому з System.Nullable, не було призначено дійсне значення T, чого в цьому не відбулося справа.
Один правильний спосіб присвоїти значення типу нульового значення звичайному типу значення - це використовувати властивість System.Nullable.HasValue, щоб встановити, чи присвоєно дійсне значення T для типу нульового значення:
int? myNullableInteger = null;
if (myNullableInteger.HasValue)
{
int myInteger = myNullableInteger.Value;
}
Іншим варіантом є використання цього синтаксису:
int? myNullableInteger = null;
int myInteger = myNullableInteger ?? -1;
За допомогою якого звичайному цілому цілому myInteger присвоюється значення нульового цілого числа "myNullableInteger", якщо останньому було призначено дійсне ціле число; в іншому випадку моєму Integer присвоюється значення -1.
Це нульовий оператор злиття, який працює аналогічно потрійному оператору.
a ?? b => a !=null ? a : b
Ще один цікавий момент для цього полягає в тому, що "зведений тип може містити значення, або воно може бути невизначеним" . Отже, якщо ви спробуєте призначити тип нульового значення ненульовому типу значення, ви отримаєте помилку часу компіляції.
int? x = null; // x is nullable value type
int z = 0; // z is non-nullable value type
z = x; // compile error will be there.
Отже, щоб зробити це, використовуючи ?? оператор:
z = x ?? 1; // with ?? operator there are no issues
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
еквівалентно
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();
Але класна річ у тому, що ви можете зав'язати їх ланцюгом, як казали інші люди. Той тонкий, який не торкався, - це те, що ви можете насправді використовувати його, щоб кинути виняток.
A = A ?? B ?? throw new Exception("A and B are both NULL");
??
Оператор називається нуль-які зливаються оператор. Він повертає лівий операнд, якщо операнд не є нульовим; в іншому випадку він повертає правий операнд.
int? variable1 = null;
int variable2 = variable1 ?? 100;
Встановити variable2
значення variable1
, якщо variable1
НЕ нульове; в іншому випадку, якщо variable1 == null
, встановити variable2
100.
Інші Null Coalescing Operator
досить добре описали . Для тих, хто цікавиться, є скорочений синтаксис, де це (питання ТА):
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
еквівалентно цьому:
FormsAuth ??= new FormsAuthenticationWrapper();
Деякі вважають його більш зрозумілим і стислим.