2016-05-17 1 views
22

Я только что обновился с VS 2010 до 2015 года. Мне нравится новый null-conditional operator, который также известен как нулевое распространение. Это позволяет упростить код, например:Оператор с нулевым условием оценивает bool не на bool? как ожидалось

string firstCustomerName = customers?[0].Name; // null if customers or the first customer is null 

еще одно:

int? count = customers?[0]?.Orders?.Count(); // null if customers, the first customer, or Orders is null 

который возвращает Nullable<int>, даже если Enumerable.Count, возвращает int дифференцироваться между действительными счетами и любым nulls ранее. Это довольно интуитивно и очень полезно.

Но почему это компилироваться и работать, как ожидалось (она возвращает false):

string text = null; 
bool contains = text?.IndexOf("Foo", StringComparison.CurrentCultureIgnoreCase) >= 0; 

Он должен либо вернуть bool? (который не делает) или не компилировать.

+5

Упс, я думаю, что у меня есть это сам, вы можете переписать его: 'int? indexof = text? .IndexOf ("Foo", StringComparison.CurrentCultureIgnoreCase); bool contains = indexof> = 0; ' –

+4

Я проголосовал за оператор'?> = '.:) –

+0

@DStanley: такой, который включает в себя другие [категории операторов] (https://msdn.microsoft.com/en-us/library/aa691323 (v = vs.71) .aspx), чем первичный? Нанесет больше вреда, чем пользы. –

ответ

28

Что вы на самом деле является

string text = null; 
int? index = text?.IndexOf("Foo", StringComparison.CurrentCultureIgnoreCase); 
bool contains = index >= 0; 

и int? >= int совершенно законно.

Причина, по которой она была разделена, состоит из the documentation for the operator. «Если одна операция в цепочке условного доступа к члену и операция индекса возвращают значение null, то остальная часть выполнения цепочки прекращается. Другие операции с более низким приоритетом в выражении продолжаются. " Это означает, что .? будет оценивать вещи с одинаковым приоритетом или выше, прежде чем «создаст значение».

Если вы посмотрите на the order of operator precedence, вы увидите, что «Операторы реляционного и точечного тестирования» значительно ниже в списке, поэтому значение будет создано до применения >=.


UPDATE: Потому что он был воспитан в комментариях, вот спецификации раздел C# 5 о том, как >= и другие операторы ведут себя при работе с обнуляемого значением. Я не мог найти документ для C# 6.

7.3.7 Приподнятых операторы

поднятых оператор разрешения предопределены и определяемого пользователь операторы, которые работают на ненулевых типах значений, которые будут также использоваться с обнуляемым Формы этих типов. Приподнятые операторы построены из предопределенных и определяемых пользователем операторов, которые отвечают определенным требованиям, а , описанной в следующем:

  • Для унарных операторов
    + ++ - -- ! ~

    поднятая форма оператора существует, если типы операндов и результатов являются неинифицируемыми типами значений. Поднятая форма - , построенная путем добавления сингла? модификатора к операнду и результата . Выбранный оператор создает нулевое значение, если операнд равен null.В противном случае, снятый оператор разворачивает операнд, применяет базовый оператор и обертывает результат.

  • Для бинарных операторов
    + - */% & |^<< >>

    поднятая форма оператора существует, если операнд и результат типа все не-обнуляемых типы значений. Поднятая форма построена по , добавив сингл? модификатора для каждого операнда и типа результата. Поднятый оператор производит нулевое значение, если один или оба операнда являются нулевыми (исключение является & и | операторами типа bool?, Как описано в §7.11.3). В противном случае, снятый оператор разворачивает операнды, применяет основного оператора и обертывает результат.

  • Для операторов равенства
    == !=

    поднятая форма оператора существует, если типы операндов оба не-обнуляемых типы значений и если тип результата является BOOL. Поднятая форма построена путем добавления сингла? модификатора для каждого операнда типа. Поднятый оператор считает два нулевых значения равными, а значение null не равно любому ненулевому значению. Если оба операнда не равны нулю, снятый оператор разворачивает операнды и применяет базовый оператор для получения результата bool.

  • Для операторов отношений
    < > <= >=

    поднятая форма оператора существует, если типы операндов оба не-обнуляемых типов значений и если тип результата является BOOL. Поднятая форма построена путем добавления сингла? модификатора для каждого операнда типа. Поднятый оператор выдает значение false, если один или оба операнда являются нулевыми. В противном случае, снятый оператор разворачивает операнды и применяет оператора-основателя для получения результата bool.

+0

Для тех из нас, кто не имеет большого знания в C#, каково поведение оператора '> =', когда 'Nullable' на самом деле является нулевым? – njzk2

+0

@ njzk2 простыми словами, если любая из сторон или с обеих сторон '> =' равна null, она всегда будет возвращать false. См. Мое обновление для полной спецификации. –

+0

thanks @ScottChamberlain – njzk2

3

Если вы используете этот код, и наведите курсор мыши на x, вы видите, что x является int?:

var x = text?.IndexOf("Foo", StringComparison.CurrentCultureIgnoreCase); 
bool contains = x >= 0; 

Так типирование по-прежнему верна.

Затем рассмотрим x >= 0: это int? >= int. По-видимому, существует оператор между обнуляемыми и не нулевыми структурами. Вот почему он работает.

Если вы посмотрите на IL, вы увидите, что на самом деле звонки HasValue и GetValueOrDefault(). Я предполагаю, что оператор делает это, но я не мог найти его в эталонном источнике, поэтому он должен быть в CLR или компилятора:

instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault() 

... 
instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue() 
+1

Правда, но могло бы быть, что оператор с нулевым условием будет включать в себя оператор '> =', который вернет 'bool? '. Но я предполагаю, что это подразумевается с [_ "другими операциями с более низким приоритетом в выражении continue" _] (https://msdn.microsoft.com/en-us/library/dn986595.aspx). –