Перейдите по этой строке кода:
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 за указание на это.)
Просто потому, что никто еще не сказал волшебные слова: это оператор нулевой коалесценции. Он определен в разделе 7.12 спецификации С# 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;
??
существует, чтобы предоставить значение для типа с нулевым значением, когда значение равно null. Итак, если formsAuth имеет значение null, он вернет новый FormsAuthenticationWrapper().
Два знака вопроса (??) указывают на то, что это оператор объединения.
Оператор объединения возвращает первое значение NON-NULL из цепочки. Вы можете увидеть это видео на YouTube, которое демонстрирует практически все это.
Но позвольте мне добавить больше к тому, что говорит видео.
Если вы видите английское значение объединения, оно говорит: "объединяйтесь". Например, ниже приведен простой объединяющий код, который объединяет четыре строки.
Таким образом, если str1
равен null
он будет пытаться использовать str2
, если str2
равен null
он будет пытаться использовать str3
и так далее, пока не найдет строку с ненулевым значением.
string final = str1 ?? str2 ?? str3 ?? str4;
Проще говоря, оператор Coalescing возвращает первое значение NON-NULL из цепочки.
Если вы знакомы с Ruby, его ||=
мне кажется сродни С# ??
. Вот некоторые 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"
И в С#:
string str1 = null;
str1 = str1 ?? "new value";
string str2 = "old value";
str2 = str2 ?? "another new value";
Это короткая рука для тернарного оператора.
FormsAuth = (formsAuth != null) ? formsAuth : new FormsAuthenticationWrapper();
Или для тех, кто не делает тройной:
if (formsAuth != null)
{
FormsAuth = formsAuth;
}
else
{
FormsAuth = new FormsAuthenticationWrapper();
}
Ничего опасного в этом нет. На самом деле это красиво. Вы можете добавить значение по умолчанию, если это желательно, например:
CODE
int x = x1 ?? x2 ?? x3 ?? x4 ?? 0;
коалесцирующий оператор
что эквивалентно
FormsAuth = formsAUth == null ? new FormsAuthenticationWrapper() : formsAuth
Только для вашего удовольствия (зная, что вы все парни С#;).
Я думаю, что он возник в Smalltalk, где он существует уже много лет. Он определяется там как:
в Object:
? anArgument
^ self
в UndefinedObject (aka nil class):
? anArgument
^ anArgument
Есть и оценка (?) и неоценивающих версий (??) этого.
Он часто встречается в методах getter для lazy-initialized private (instance) переменных, которые остаются нулевыми до тех пор, пока они действительно не нужны.
Некоторые из примеров здесь получения значений с использованием коалесценции являются неэффективными.
Что вы действительно хотите:
return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();
или
return _formsAuthWrapper ?? (_formsAuthWrapper = new FormsAuthenticationWrapper());
Это предотвращает воссоздание объекта каждый раз. Вместо частной переменной, остающейся пустой, и создания нового объекта по каждому запросу, это обеспечивает приватную переменную, если новый объект создан.
Как правильно указывалось в многочисленных ответах, это "оператор слияния нулей" (??), о котором можно также упомянуть его двоюродного брата "Оператор с нулевым условием" (?. Или ? [), Который является оператором, который много раз он используется в сочетании с ??
Используется для проверки на нулевое значение перед выполнением операции доступа к члену (?.) Или индекса (? [). Эти операторы помогают вам написать меньше кода для обработки нулевых проверок, особенно для спуска в структуры данных.
Например:
// 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;
что более многословно и громоздко.
Я прочитал целую эту тему и многие другие, но я не могу найти столь же полный ответ, как это.
С помощью которого я полностью понял "зачем использовать?" и когда использовать? и как использовать??.
Основы коммуникаций Windows, выпущенные Craig McMurtry ISBN 0-672-32948-4
Существуют две общие причины, в которых хотелось бы узнать, значение присваивается экземпляру типа значения. Во-первых, когда экземпляр представляет значение в базе данных. В таком случае вы хотели бы иметь возможность изучить экземпляр, чтобы выяснить, действительно ли значение присутствует в базе данных. Другое обстоятельство, которое более уместно для предмета этой книги, - это когда экземпляр представляет элемент данных, полученный из какого-то удаленного источника. Опять же, хотелось бы определить из экземпляра, было ли получено значение для этого элемента данных.
В .NET Framework 2.0 используется общее определение типа, которое предусматривает такие случаи, когда требуется назначить значение 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);
}
Язык программирования С# предоставляет сокращенный синтаксис для объявления типов построенный из System.Nullable. Этот синтаксис позволяет сокращать:
System.Nullable<int> myNullableInteger;
к
int? myNullableInteger;
Компилятор не позволит одному из способов присвоить значение типа значения NULL для обычного типа значений следующим образом:
int? myNullableInteger = null;
int myInteger = myNullableInteger;
Это не позволяет сделать это, потому что тип значения с нулевым значением может иметь значение 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
равно NULL; в противном случае, если variable1 == null
, установите variable2
100.