.Net 2+:почему if( 1 == null ) больше не выдает исключение компилятора?
-
09-06-2019 - |
Вопрос
Я использую 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?
обнуляется и 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
?
Решение
Я не думаю, что это проблема компилятора как таковой;целочисленное значение никогда не бывает нулевым, но идея их приравнивания не является недопустимой;это допустимая функция, которая всегда возвращает 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>'
.
Поэтому, если вы хотите вернуть ошибку компилятора, перейдите в свойства проекта и включите "рассматривать предупреждения как ошибки" для этой ошибки, и вы снова начнете видеть в них проблемы, связанные с нарушением сборки.
Другие советы
Странно ...компилирую это с помощью 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
Можете ли вы опубликовать фрагмент кода?
Компилятор по-прежнему генерирует предупреждение, когда вы сравниваете ненулевой тип с null, что именно так и должно быть.Возможно, ваш уровень предупреждения слишком низок или это было изменено в последних версиях (я сделал это только в .net 3.5).
Платформа 2.0 ввела тип значения, допускающий обнуление.Несмотря на то, что литеральная константа "1" никогда не может быть нулевой, ее базовый тип (int) теперь может быть приведен к нулевому типу int.Я предполагаю, что компилятор больше не может предполагать, что типы int не являются обнуляемыми, даже если это литеральная константа.Я действительно получаю предупреждение при компиляции 2.0:
Предупреждение 1 Результатом выражения всегда является 'false', поскольку значение типа 'int' никогда не равно 'null' типа 'int?'
Предупреждение новое (3.5, я думаю) - ошибка такая же, как если бы я сделал 1 == 2
, что он достаточно умен, чтобы признать как никогда верным.
Я подозреваю, что при полной оптимизации 3.5 все утверждение будет просто удалено, так как оно довольно умное и никогда не дает истинных оценок.
В то время как я, возможно, захочу 1==2
для компиляции (например, для отключения функционального блока, пока я тестирую что-то еще) Я не хочу 1==null
Для.
Это должна быть ошибка времени компиляции, потому что типы несовместимы (типы значений никогда не могут быть нулевыми).Довольно печально, что это не так.