it-roy-ru.com

Что означают два знака вопроса вместе в C #?

Наткнулся на эту строку кода:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

Что означают два вопросительных знака, это какой-то троичный оператор? Сложно найти в Google.

1412
Edward Tanguay

Это нулевой оператор слияния, и он очень похож на троичный (немедленный, если) оператор. Смотрите также ?? Оператор - 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 за указание на это.)

1900
lc.

Просто потому, что никто еще не сказал волшебные слова: это оператор null coalescing. Это определено в разделе 7.12 спецификации языка C # 3.0 .

Это очень удобно, особенно из-за способа работы, когда оно используется в выражении несколько раз. Выражение формы:

a ?? b ?? c ?? d

выдаст результат выражения a, если оно не равно нулю, в противном случае попробуйте b, в противном случае попробуйте c, в противном случае попробуйте d. Это короткое замыкание в каждой точке.

Кроме того, если тип d не обнуляется, тип целого выражения также не обнуляется.

254
Jon Skeet

Это нулевой оператор объединения.

http://msdn.Microsoft.com/en-us/library/ms173224.aspx

Да, почти невозможно искать, если вы не знаете, как это называется! :-)

Правка: И это классная особенность из другого вопроса. Вы можете связать их.

Скрытые возможности C #?

67
Iain Holder

Спасибо всем, вот самое краткое объяснение, которое я нашел на сайте MSDN:

// y = x, unless x is null, in which case y = -1.
int y = x ?? -1;
24
Edward Tanguay

?? предназначен для предоставления значения для обнуляемого типа, когда значение равно нулю. Таким образом, если formsAuth равен нулю, он вернет новый FormsAuthenticationWrapper (). 

20
RedFilter

enter image description here

Два знака вопроса (??) указывают на то, что это оператор объединения.

Оператор объединения возвращает первое значение NON-NULL из цепочки. Вы можете увидеть это видео на YouTube которое демонстрирует практически все это.

Но позвольте мне добавить больше к тому, что говорит видео.

Если вы видите английское значение объединения, оно говорит: «объединяйтесь». Например, ниже приведен простой объединяющий код, который объединяет четыре строки.

Поэтому, если str1 равен null, он будет пытаться использовать str2, если str2 равен null, он будет пытаться использовать str3 и так далее, пока не найдет строку с ненулевым значением.

string final = str1 ?? str2 ?? str3 ?? str4;

Проще говоря, оператор Coalescing возвращает первое значение NON-NULL из цепочки. 

18
Shivprasad Koirala

Если вы знакомы с Ruby, мне кажется, что его ||= сродни ?? в 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";
12
Sarah Vessels

Ничего опасного в этом нет. На самом деле это красиво. Вы можете добавить значение по умолчанию, если это желательно, например:

КОД

int x = x1 ?? x2 ?? x3 ?? x4 ?? 0;
11
dqninh

Это короткая рука для троичного оператора. 

FormsAuth = (formsAuth != null) ? formsAuth : new FormsAuthenticationWrapper();

Или для тех, кто не делает троичный

if (formsAuth != null)
{
  FormsAuth = formsAuth;
}
else
{
  FormsAuth = new FormsAuthenticationWrapper();
}
11
Benjamin Autin

оператор объединения

это эквивалентно

FormsAuth = formsAUth == null ? new FormsAuthenticationWrapper() : formsAuth
10
aku

Только для вашего удовольствия (зная, что вы все ребята из C # ;-).

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

в объекте:

? anArgument
    ^ self

в UndefinedObject (он же класс nil):

? anArgument
    ^ anArgument

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

10
blabla999

Некоторые примеры получения значений с использованием коалесценции здесь неэффективны.

То, что вы действительно хотите, это:

return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();

или же

return _formsAuthWrapper ?? (_formsAuthWrapper = new FormsAuthenticationWrapper());

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

9
KingOfHypocrites

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

Нулевой оператор

Используется для проверки на нулевое значение перед выполнением операции доступа к члену (?.) Или индекса (? [). Эти операторы помогают вам написать меньше кода для обработки нулевых проверок, особенно для спуска в структуры данных.

Например: 

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

что более многословно и громоздко.

9
brakeroo

Заметка:

Я прочитал всю эту ветку и многие другие, но не могу найти столь же исчерпывающий ответ, как этот.

По которому я полностью понял «зачем использовать ?? и когда использовать ?? и как использовать ??».

Источник:

Крейг МакМертри выпустил фундамент Windows Communication ISBN 0-672-32948-4

Типы значений Nullable

Существует два распространенных обстоятельства, при которых хотелось бы узнать, было ли Значение присвоено экземпляру типа значения. Первый - когда экземпляр представляет значение в базе данных. В таком случае хотелось бы иметь возможность проверить экземпляр, чтобы выяснить, действительно ли значение присутствует в базе данных. Другое обстоятельство, которое больше относится к предмету этой книги, - это когда экземпляр представляет элемент данных, полученный из какого-то удаленного источника. Опять же, хотелось бы определить из экземпляра, было ли получено значение для этого элемента данных.

.NET Framework 2.0 включает определение универсального типа, которое предусматривает случаи, подобные этим, в которых нужно присвоить значение NULL экземпляру типа значения и проверить, является ли значение экземпляра NULL. Это определение универсального типа - System.Nullable, которое ограничивает аргументы универсального типа, которые могут быть заменены на T, типами значений Экземплярам типов, созданным из System.Nullable, может быть присвоено значение null; действительно, их значения по умолчанию равны нулю. Таким образом, типы, созданные из System.Nullable, могут упоминаться как типы значений, допускающие значение NULL. . 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;

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

int? myNullableInteger = null;
int myInteger = myNullableInteger;

Это не позволяет сделать это, потому что тип значения NULL может иметь значение NULL, которое в действительности будет иметь в этом случае, и это значение не может быть присвоено обычному типу значения. Хотя компилятор разрешил бы этот код,

int? myNullableInteger = null;
int myInteger = myNullableInteger.Value;

Второй оператор вызовет исключение, потому что любая попытка Получить доступ к свойству System.Nullable.Value является недопустимой операцией, если типу .__, созданному из System.Nullable, не было присвоено допустимое значение T, чего не произошло в этом случае.

Заключение:

Один правильный способ присвоить значение типа значения, допускающего значение NULL, обычному типу значения - это использовать свойство System.Nullable.HasValue, чтобы определить, было ли назначено допустимое значение T для типа значения, допускающего значение NULL:

int? myNullableInteger = null;
if (myNullableInteger.HasValue)
{
int myInteger = myNullableInteger.Value;
}

Другой вариант - использовать этот синтаксис:

int? myNullableInteger = null;
int myInteger = myNullableInteger ?? -1;

С помощью которого обычному целому числу myInteger присваивается значение обнуляемого целого числа «myNullableInteger», если последнему присвоено допустимое целочисленное значение; в противном случае myInteger присваивается значение -1.

7
Wiqi

Оператор ?? называется оператором слияния нулей. Возвращает левый операнд, если операнд не равен нулю; в противном случае он возвращает правый операнд.

int? variable1 = null;
int variable2  = variable1 ?? 100;

Установите для variable2 значение variable1, если variable1 НЕ является нулевым; В противном случае, если variable1 == null, установите для variable2 значение 100.

0
Md.Jubayer

Это нулевой оператор объединения, который работает аналогично троичному оператору.

    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
0
Ashish Mishra
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

эквивалентно 

FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();

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

A = A ?? B ?? throw new Exception("A and B are both NULL");
0
NolePTR