Наткнулся на эту строку кода:
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
(если все ответы имеют значение NULL, то значение Answer
NULL):
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
Да, почти невозможно искать, если вы не знаете, как это называется! :-)
РЕДАКТИРОВАТЬ: И это классная особенность из другого вопроса. Вы можете связать их
Спасибо всем, вот самое краткое объяснение, которое я нашел на сайте 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
.
Два знака вопроса (??) указывают на то, что это оператор объединения.
Оператор объединения возвращает первое значение 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 оба неявно принимают введенные вами значения.
Если вы знакомы с 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";
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
). «Обнуляемый тип» здесь включает , конечно, как обнуляемые типы значений, так и ссылочные типы. Это ошибка времени компиляции, если одна или несколько цепочечных переменных (кроме последней) не обнуляются.
Как правильно указывалось в многочисленных ответах, это «оператор слияния нулей» ( ?? ), о котором можно также упомянуть его двоюродного брата « оператор с нулевым условием» ( ? Или ? [ ), Который является оператором, который много раз он используется в сочетании с ??
Используется для проверки на нулевое значение перед выполнением операции доступа к члену ( ?. ) Или операции индекса ( ? [ ). Эти операторы помогают вам писать меньше кода для обработки нулевых проверок, особенно для перехода в структуры данных.
Например:
// 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 (он же класс nil):
? anArgument
^ anArgument
Существуют как оценочные (?), Так и не оценивающие версии (??) этого.
Это часто встречается в методах-получателях для приватных инициализируемых переменных (экземпляра), которые остаются нулевыми до тех пор, пока они действительно не понадобятся.
Некоторые примеры получения значений с использованием коалесценции здесь неэффективны.
То, что вы действительно хотите, это:
return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();
или
return _formsAuthWrapper ?? (_formsAuthWrapper = new FormsAuthenticationWrapper());
Это предотвращает воссоздание объекта каждый раз. Вместо того, чтобы приватная переменная оставалась нулевой, а новый объект создавался при каждом запросе, это гарантирует, что приватная переменная будет назначена, если будет создан новый объект.
??
оценивается ли короткий путь? new FormsAuthenticationWrapper();
оценивается тогда и только тогда, когда _formsAuthWrapper
ноль.
Я прочитал всю эту ветку и многие другие, но не могу найти такой исчерпывающий ответ, как этот.
По которому я полностью понял «зачем использовать ?? и когда использовать ?? и как использовать ??."
Основа коммуникации Windows выпущена Крейгом МакМертри ISBN 0-672-32948-4
Существует два распространенных обстоятельства, в которых хотелось бы узнать, было ли присвоено значение экземпляру типа значения. Первый - это когда экземпляр представляет значение в базе данных. В таком случае хотелось бы иметь возможность изучить экземпляр, чтобы выяснить, действительно ли значение присутствует в базе данных. Другое обстоятельство, которое в большей степени относится к предмету этой книги, - это когда экземпляр представляет элемент данных, полученный из некоторого удаленного источника. Опять же, хотелось бы определить из экземпляра, было ли получено значение для этого элемента данных.
.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.
Это нулевой оператор объединения, который работает аналогично троичному оператору.
a ?? b => a !=null ? a : b
Еще один интересный момент для этого: «Обнуляемый тип может содержать значение или он может быть неопределенным» . Таким образом, если вы попытаетесь назначить тип значения NULL для значения NULL, вы получите ошибку во время компиляции.
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
довольно хорошо. Для тех, кто заинтересован, существует сокращенный синтаксис, где это (вопрос SO):
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
эквивалентно этому:
FormsAuth ??= new FormsAuthenticationWrapper();
Некоторые считают его более читаемым и лаконичным.