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

Перейдите по этой строке кода:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

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

Ответ 1

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

Ответ 2

Просто потому, что никто еще не сказал волшебные слова: это оператор нулевой коалесценции. Он определен в разделе 7.12 спецификации С# 3.0.

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

a ?? b ?? c ?? d

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

enter image description here

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

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

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

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

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

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

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

Ответ 7

Если вы знакомы с 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";

Ответ 8

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

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

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

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

Ответ 9

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

CODE

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

Ответ 10

коалесцирующий оператор

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

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

Ответ 11

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

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

в Object:

? anArgument
    ^ self

в UndefinedObject (aka nil class):

? anArgument
    ^ anArgument

Есть и оценка (?) и неоценивающих версий (??) этого.
Он часто встречается в методах getter для lazy-initialized private (instance) переменных, которые остаются нулевыми до тех пор, пока они действительно не нужны.

Ответ 12

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

Что вы действительно хотите:

return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();

или

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

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

Ответ 13

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

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

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

Например:

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

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

Ответ 14

Примечание:

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

С помощью которого я полностью понял "зачем использовать?" и когда использовать? и как использовать??.

Источник:

Основы коммуникаций 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. ​​

Ответ 15

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

    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

Ответ 16

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

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

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

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

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

Ответ 17

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

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

Установите variable2 в значение variable1, если variable1 равно NULL; в противном случае, если variable1 == null, установите variable2 100.