если условие с обнуляемым - PullRequest
7 голосов
/ 18 января 2012

Существует множество синтаксических символов сахара с Nullable<T>, таких как:

int? parsed to Nullable<int>

int? x = null
   if (x != null) // Parsed to if (x.HasValue)

x = 56; // Parsed to x.Value = 56;

и т. Д.

Почему if условие с Nullable не работает?

if (x)
{} 

Получается ошибка Complier, говорящая о невозможности преобразования Nullable<bool> в bool.
Почему он не анализируется в if (x.HasValue && x.Value == true) или что-то подобное?

Это наиболее очевидное использованиедля Nullable<bool>

Ответы [ 10 ]

22 голосов
/ 18 января 2012

Это наиболее очевидное использование для Nullable<bool>

Ваше "очевидное" поведение приводит ко многим неочевидным поведениям.

Если

if(x)

считается ложным, когда x равен нулю, тогда что должно произойти с

if(!x)

?!x также равно нулю, когда x равно нулю, и поэтому будет также рассматриваться как ложное!Не кажется ли странным, что вы не можете изменить поведение условного выражения с помощью инверсии?

Как насчет

if (x | !x)

Конечно, это всегда должно быть правдой, но если x равно нулю, тогда целоевыражение равно нулю и, следовательно, ложно.

Лучше избегать этих неочевидных ситуаций, просто делая их незаконными.C # - это «заставить пользователя говорить то, что он имеет в виду однозначно».

Я считаю, что VB ведет себя так, как вы хотите.Вы можете подумать о переходе на VB, если вам это нравится.

11 голосов
/ 18 января 2012

Проще говоря, он не компилируется, потому что в спецификации сказано, что он должен - условие if требует логического выражения - и выражение типа Nullable<bool> не является логическим -expression

A логическое выражение - это выражение, которое дает результат типа bool; либо напрямую, либо через применение оператора true в определенных контекстах, как указано в следующем.

Тем не менее, легко обойти:

if (x.GetValueOrDefault())
{
}

Или, чтобы быть более ясным:

if (x ?? false)
{
}

Последний подход полезен, поскольку он означает, что вы можете легко изменить поведение, если x равно нулю, просто изменив его на x ?? true.

5 голосов
/ 18 января 2012

Не так очевидно, что ноль должен означать ложь. Нулевое значение означает, что значение неизвестно или неинициализировано. Неизвестно, является ли значение истинным или ложным. Кто сказал, что нуль должен вести себя как ложь?

Более очевидное использование для Nullable<bool> - хранить что-то, что может быть либо истинным, либо ложным, но иногда не имеет значения или неизвестно, в этом случае значение равно нулю.

3 голосов
/ 18 января 2012

Я думаю, что это не очень хорошая идея. То, что null оценивается как ложное, не кажется естественным. Особенно в if+else заявлениях. Поэтому принудительно указывать пользователю: if(nb==true) и if(nb==false) - хорошая идея IMO.

MSDN говорит:

bool? b = null;
if (b) // Error CS0266.
{
}

Это недопустимо, потому что неясно, что означает нуль в контексте условия. Использовать bool? в условном выражении сначала проверьте его свойство HasValue, чтобы убедиться, что его значение не равно нулю, а затем приведите его к типу bool. Для получения дополнительной информации см. Bool. Если вы выполняете приведение на бул? со значением null в условном тесте будет выдано исключение InvalidOperationException.

http://msdn.microsoft.com/en-us/library/bb384091.aspx

Некоторые из ответов на мой вопрос Почему нет отмененных операторов короткого замыкания в `bool?`? также касаются этих аспектов

2 голосов
/ 18 января 2012

Это наиболее очевидное использование для Nullable

Будьте осторожны с такими утверждениями. То, что кажется очевидным для вас, не обязательно является очевидным для кого-то еще.

Кроме того,

if(x) {}

также было бы недопустимым, если бы х был ссылочным типом, поэтому в интересах согласованности поведение должно быть одинаковым для Nullables.

2 голосов
/ 18 января 2012

Технически это не работает, потому что Nullable<T> не определяет оператор преобразования в bool.

Практически это не поддерживается по ряду причин, включая:

  • В C # нет неявных преобразований в bool - почему они должны быть в Nullable<T>?
  • Любое доступное преобразование должно быть объявлено для каждого T в Nullable<T> - какэто возможно, когда вы можете подключить свой собственный тип как T, о котором компилятор ничего не знает?
  • Какая семантика if(!x)?
1 голос
/ 18 января 2012

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

int x1 = 7;
int? x2 = x1;

но вы не можете сделать это:

int? x1 = 7;
int x2 = x1;

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

1 голос
/ 18 января 2012

Подумайте, что произойдет в этом случае, тогда

bool? nullBool = null;
if (nullBool)
{
    someCode();
}

Невозможно определить, вошел ли он в предложение if, потому что bool был нулевым или ложным. Это, вероятно, не желательно

1 голос
/ 18 января 2012

Вы не можете сделать

if (x)
{...}

по той же причине, по которой вы не можете написать

int? a = null;
var b = a + 1;

Обнуляемый логический тип не является логическим.В каких случаях вы хотите считать пустой бул?как правда, и иногда вы хотите считать это ложным.Языковой дизайн не принимает такое решение за вас.

1 голос
/ 18 января 2012

Все, что находится в скобках из оператора if, должно иметь значение true или false. Обнуляемый bool может принимать значение null, true или false.

...