Почему TimeSpan и Структуры Гуида могут сравниться с пустым указателем?

Если Вы вставляете в единственную таблицу, можно записать запрос как это (возможно, только в MySQL):

INSERT INTO table1 (First, Last)
VALUES
    ('Fred', 'Smith'),
    ('John', 'Smith'),
    ('Michael', 'Smith'),
    ('Robert', 'Smith');
18
задан dtroy 4 August 2009 в 06:36
поделиться

5 ответов

Это оператор == .

Класс TimeSpan содержит перегрузку оператора равенства:

public static bool operator ==(DateTime d1, DateTime d2)
{
     return (t1._ticks == t2._ticks);
}

Само по себе это не " t делают возможным сравнение с null , , но ...

С появлением типов, допускающих значение NULL, каждая структура неявно преобразуется в свой тип, допускающий значение NULL , поэтому, когда вы видите что-то вроде

TimeSpan y = new TimeSpan();
if (y == null)
    return;

, вы не видите , что это происходит:

TimeSpan y = new TimeSpan();
if ((Nullable<TimeSpan>)y == (Nullable<TimeSpan>)null)
    return;

Null получает неявное преобразование (неявное присвоение?), но не все Система .Object объекты делают:

TimeSpan y = new TimeSpan();
object o = null;
if (y == o) //compiler error
    return;

Хорошо, но оператор равенства не принимает аргументы, допускающие значение NULL, не так ли?

Что ж, здесь может помочь msdn , заявив:

Предопределенные унарные и двоичные операторы и любые определяемые пользователем операторы, существующие для типов значений также может использоваться типами, допускающими значение NULL. Эти операторы производят нулевое значение если [любой из] операндов равен нулю; иначе, оператор использует содержащееся значение для вычисления результата.

Таким образом, вы фактически получаете реализацию, допускающую значение NULL, для каждого оператора бесплатно с фиксированным определенным поведением. Упомянутое выше «содержащееся значение» - это фактическое значение, которое вернет оператор, не допускающий значения NULL.

14
ответ дан 30 November 2019 в 07:33
поделиться

Эта проблема эффективно возникла, когда были включены типы, допускающие значение NULL. Существует неявное преобразование из TimeSpan в TimeSpan? , и есть сравнение между TimeSpan? и нулевым значением этого типа.

Компилятор выдает предупреждение для некоторых типов, которое проясняет, что он пытается сделать:

int x = 10;
if (x == null)
{
    Console.WriteLine();
}

Дает это предупреждение:

Test.cs(9,13): warning CS0472: The result of the expression is always 'false'
       since a value of type 'int' is never equal to 'null' of type 'int?'

Я считаю, что Марк Гравелл и я разработали обстоятельства, при которых предупреждение выдается один раз ... жаль, что это не соответствует .

7
ответ дан 30 November 2019 в 07:33
поделиться

Этот случай для дженериков рассматривается в разделе 7.9.6 спецификации языка C #.

Конструкция x == null разрешена, даже если T может представлять тип значения, а результат просто определяется как false, когда T является типом значения.

Я немного покопался в спецификации и не смог ' Я не найду более общего правила. Ответ Джона указывает на то, что это проблема с продвижением, допускающая значение NULL.

Это правило (или аналогичный вариант), похоже, здесь применяется. Если вы внимательно посмотрите на отраженный результат, вы заметите, что сравнения нет. Компилятор C #, очевидно, оптимизирует это сравнение и заменяет его на false.

Например, если вы наберете следующее

var x = new TimeSpan();
var y = x == null;
Console.WriteLine(x);

Затем декомпилируете его, вы увидите следующее

var x = new TimeSpan();
var y = false;
Console.WriteLine(x);
7
ответ дан 30 November 2019 в 07:33
поделиться

См. Также: C # 3 (.NET 3.5) версия csc не сообщает CS0162 о невозможности получения кода (struct / null)

Начиная с компилятора C # 3, что означает иногда даже не предупреждает вас об этом ;-p

Поскольку Guid / TimeSpan и т.д. предоставляют == , они попадают в эту ловушку, где не Не предупреждаю.

4
ответ дан 30 November 2019 в 07:33
поделиться

Я НАШЕЛ ЭТО :)

Следующее дает предупреждение:

int i = 0;
if (i == null)
// ^^ Warning: The result of the expression is always 'false' since a value of
//             type 'int' is never equal to 'null' of type 'int?'

Компилятор просто не может правильно выдать предупреждение о том, что null вы typed был преобразован в тип TimeSpan? для сравнения.

Изменить: соответствующий раздел в спецификации - §13.7.1, в котором говорится, что null может быть неявно преобразован в любой тип, допускающий значение NULL , и (очень трудный для чтения) раздел §13.7.2, в котором указывается, что тип значения T может быть неявно преобразован в T? .

Первоначально я писал:

Что бы ни происходило, это что-то в спецификации C #, потому что, как говорит JaredPar, он компилируется просто с false .

Обратите внимание, что это не компилируется:

TimeSpan ts = new TimeSpan();
object o = null;
if (ts == o) // error, Operator '==' cannot be applied to operands of type 'System.TimeSpan' and 'object'
    ...
3
ответ дан 30 November 2019 в 07:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: