.Net 2+: почему if (1 == null) больше не генерирует исключение компилятора? - PullRequest
5 голосов
/ 15 сентября 2008

Я использую 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?

Ответы [ 6 ]

3 голосов
/ 15 сентября 2008

Я не думаю, что это проблема компилятора per se ; целочисленное значение никогда не бывает нулевым, но идея приравнивать их не является недействительной; это действительная функция, которая всегда возвращает 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>'.

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

3 голосов
/ 15 сентября 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

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

1 голос
/ 15 сентября 2008

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

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

1 голос
/ 15 сентября 2008

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

0 голосов
/ 15 сентября 2008

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

0 голосов
/ 15 сентября 2008

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

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

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

...