Почему требуется явное преобразование после проверки на null?
int foo;
int? bar;
if (bar != null)
{
foo = bar; // does not compile
foo = (int)bar; // compiles
foo = bar.Value; // compiles
}
Я давно знаю, что первое утверждение неверно, но оно всегда меня било. Я проверял, что bar
не является нулевым, так почему компилятор жалуется?
Ответы
Ответ 1
Тип bar
все еще int?
, и нет никакого неявного преобразования от int?
до int
.
Условие не меняет срок действия более позднего кода. То же самое относится и к другим приведениям:
object x = ...;
if (x is string)
{
string y = x; // This is still invalid
string z = (string) x; // This is fine
}
Компилятор редко использует результат одной части кода, чтобы повлиять на действительность другого. В качестве еще одного примера:
bool condition = ...;
string x;
if (condition)
{
x = "yes";
}
if (!condition)
{
x = "no";
}
Console.WriteLine(x); // Invalid
Последняя строка недействительна, поскольку x
по-прежнему не определен. Мы знаем, что независимо от значения x
, мы введем одно из этих операторов выражения if
... но компилятор не пытается понять это.
Хотя это может показаться глупым, это значительно упрощает правила языка.
Ответ 2
Сравнение говорит только: это не null
, компилятор все еще использует тип, чтобы узнать, можно ли назначить назначение.
После этого компиляция даже без нулевой проверки.
foo = (int)bar;
Ответ 3
Компилятор проверяет, является ли ваша программа синтаксически правильной. Он не заботится о вашей нулевой проверке.
Компилятор видит, что вы можете потерять информацию, присваивающую int? к int, и поэтому он жалуется.
Ответ 4
Представьте себе: что, если у вас была переменная-член, введенная как Nullable<int>
, к которой был обращен несколько потоков. Давайте посмотрим на ваш код при таких обстоятельствах.
if(foo != null)
{
// expensive operation that takes time.
// what if another thread as nulled foo in the meantime?
int bar = foo;
}