.Net 2+: почему if( 1 == null ) больше не вызывает исключение компилятора?

Я использую int в качестве примера, но это относится к любому типу значения в .Net.

В .Net 1 следующее вызовет исключение компилятора:

int i = SomeFunctionThatReturnsInt();

if( i == null ) //compiler exception here

Теперь (в .Net 2 или 3.5) это исключение исчезло.

Я знаю, почему это:

int? j = null; //nullable int

if( i == j )   //this shouldn't throw an exception

Проблема в том, что поскольку int? допускает значение NULL, а int теперь имеет неявное приведение к int?. Приведенный выше синтаксис — это магия компилятора. На самом деле мы делаем:

Nullable<int> j = null; //nullable int

//compiler is smart enough to do this
if( (Nullable<int>) i == j)   

//and not this
if( i == (int) j)

Итак, теперь, когда мы делаем i == null, мы получаем:

if( (Nullable<int>) i == null )

Учитывая, что C# все равно выполняет логику компилятора для вычисления этого, почему он не может быть достаточно умным, чтобы не делать этого при работе с абсолютными значениями, такими как null?


person Keith    schedule 15.09.2008    source источник


Ответы (6)


Я не думаю, что это проблема компилятора сама по себе; целочисленное значение никогда не бывает нулевым, но идея их приравнивания не является недопустимой; это допустимая функция, которая всегда возвращает false. И компилятор знает; код

bool oneIsNull = 1 == null;

компилируется, но компилятор выдает предупреждение: The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type '<null>'.

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

person Steve Cooper    schedule 15.09.2008

Странно... компиляция с VS2008, нацеленная на .NET 3.5:

static int F()
{
    return 42;
}

static void Main(string[] args)
{
    int i = F();

    if (i == null)
    {
    }
}

Я получаю предупреждение компилятора

warning CS0472: The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type 'int?'

И он генерирует следующий IL... который, предположительно, JIT оптимизирует

L_0001: call int32 ConsoleApplication1.Program::F()
L_0006: stloc.0 
L_0007: ldc.i4.0 
L_0008: ldc.i4.0 
L_0009: ceq 
L_000b: stloc.1 
L_000c: br.s L_000e

Можете ли вы опубликовать фрагмент кода?

person Rob Walker    schedule 15.09.2008
comment
Компилятор правильно определяет, что это никогда не бывает так, как если бы вы сделали 1 == 2. Он достаточно умен, чтобы знать, что int можно неявно преобразовать в int? а это инт? можно сравнить с нулем. Я подозреваю, что оптимизатор достаточно умен, чтобы удалить весь блок. - person Keith; 15.09.2008

Компилятор по-прежнему генерирует предупреждение, когда вы сравниваете необнуляемый тип с нулевым, как и должно быть. Возможно, ваш уровень предупреждения слишком низок или это было изменено в последних версиях (я сделал это только в .net 3.5).

person ima    schedule 15.09.2008

Платформа 2.0 представила тип значения, допускающий значение NULL. Несмотря на то, что литеральная константа «1» никогда не может быть нулевой, ее базовый тип (int) теперь может быть приведен к типу Nullable int. Я предполагаю, что компилятор больше не может предполагать, что типы int не могут принимать значения NULL, даже если это буквальная константа. Я получаю предупреждение при компиляции 2.0:

Предупреждение 1. Результатом выражения всегда является «ложь», поскольку значение типа «int» никогда не равно «null» типа «int?».

person Michael Meadows    schedule 15.09.2008
comment
Как я уже сказал, компилятор знает, что int можно неявно преобразовать в int? и инт? можно сравнить с нулем. Предупреждение является общим для любого никогда не истинного сравнения. 1==2 выдаст такое же предупреждение. - person Keith; 15.09.2008

Предупреждение новое (думаю, 3.5) - ошибка такая же, как если бы я сделал 1 == 2, что достаточно умно, чтобы определить, что это никогда не было правдой.

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

Хотя я мог бы захотеть, чтобы 1==2 скомпилировался (например, чтобы отключить функциональный блок, когда я тестирую что-то еще), я не хочу, чтобы 1==null делал это.

person Keith    schedule 15.09.2008

Это должно быть ошибкой времени компиляции, потому что типы несовместимы (типы значений никогда не могут быть нулевыми). Очень грустно, что это не так.

person DrPizza    schedule 15.09.2008
comment
Прочитайте весь вопрос, я объясню, почему это происходит. Вопрос в том, почему это нельзя рассматривать как частный случай. - person Keith; 15.09.2008
comment
Когда я говорю «должен», я имею в виду моральный императив, а не то, что я ожидаю от компилятора. Обоснование, которое вы описываете, ничуть не убедительно; они должны сделать это статической ошибкой компиляции. - person DrPizza; 17.09.2008