Я столкнулся с этим сегодня, и понятия не имейте, почему компилятор C# не бросает ошибку.
Int32 x = 1;
if (x == null)
{
Console.WriteLine("What the?");
}
Я смущен относительно того, как x мог когда-либо возможно быть пустым. Тем более, что это присвоение определенно бросает ошибку компилятора:
Int32 x = null;
Действительно ли возможно, что x мог стать пустым, Microsoft просто решила не поместить, это зарегистрировалось в компиляторе, или это было пропущено полностью?
Обновление: После питания с кодом для написания этой статьи внезапно компилятор придумал предупреждение, что выражение никогда не будет верно. Теперь я действительно потерян. Я поместил объект в класс, и теперь предупреждение ушло, но уехало с вопросом, может тип значения заканчивать тем, что был пустым.
public class Test
{
public DateTime ADate = DateTime.Now;
public Test ()
{
Test test = new Test();
if (test.ADate == null)
{
Console.WriteLine("What the?");
}
}
}
Это законно, потому что разрешение перегрузки оператора имеет уникальный лучший выбор. Есть оператор ==, который принимает два nullable ints. Локальная int преобразуется в nullable int. Нулевой литерал преобразуется в nullable int. Следовательно, это легальное использование оператора ==, и всегда будет приводить к false.
Аналогично, мы также позволяем сказать "if (x == 12.6)", что также всегда будет ложным. int local конвертируется в double, литерал конвертируется в double, и очевидно, что они никогда не будут равны.
. Тип значения не может быть нулем
, хотя может быть равен нулю
(обратите внимание на Nullable<>
). В вашем случае переменная int
и null
неявно присваиваются к Nullable
и сравниваются.
Нет, Int32 x
никогда не станет нулем
.
Если вы сравниваете int с нулем. затем оператор сравнения, который применим два int?s.
"Почему сравнение типа значения с нулем является предупреждением?" статья поможет вам.
Это не ошибка, так как происходит (int?
) приведение, а предупреждение в приведенном примере:
Результатом выражения всегда является 'false', так как значение типа 'int' никогда не бывает равно 'null' типа 'int? '
Если вы проверите IL, то увидите, что она полностью удаляет недоступную ветку - ее нет в сборке релиза.
Однако, следует заметить, что она не выдает это предупреждение для пользовательских структур с операторами равенства. Так было в 2.0, но не в компиляторе 3.0. Код все равно удален (чтобы знать, что код недоступен), но предупреждение не выдается:
using System;
struct MyValue
{
private readonly int value;
public MyValue(int value) { this.value = value; }
public static bool operator ==(MyValue x, MyValue y) {
return x.value == y.value;
}
public static bool operator !=(MyValue x, MyValue y) {
return x.value != y.value;
}
}
class Program
{
static void Main()
{
int i = 1;
MyValue v = new MyValue(1);
if (i == null) { Console.WriteLine("a"); } // warning
if (v == null) { Console.WriteLine("a"); } // no warning
}
}
С IL (для Main
) - обратите внимание все , кроме MyValue(1)
(который мог иметь побочные эффекты), было удалено:
.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] int32 i,
[1] valuetype MyValue v)
L_0000: ldc.i4.1
L_0001: stloc.0
L_0002: ldloca.s v
L_0004: ldc.i4.1
L_0005: call instance void MyValue::.ctor(int32)
L_000a: ret
}
это в основном:
private static void Main()
{
MyValue v = new MyValue(1);
}
Я подозреваю, что компилятор просто оптимизирует ваш конкретный тест при генерации IL, так как тест никогда не будет ложным.
Боковая заметка: Возможно вместо этого использовать Int32? x.
. Тот факт, что сравнение никогда не может быть правдой, не означает, что оно незаконно. Тем не менее, нет, тип значения никогда не может быть null
.
Полагаю, это потому, что "==" - это синтаксический сахар, который на самом деле представляет собой вызов метода System.Object.Equals
, который принимает параметр System.Object
. Null по спецификации ECMA является специальным типом, который, конечно, является производным от System.Object
.
Поэтому есть только предупреждение.
.