Подтвердить что ты не робот

Guid == null не должен быть разрешен компилятором

Возможный дубликат:
С# в порядке со сравнением типов значений с нулем

Поведение, описанное ниже, специфично только для .net-3.5

Здравствуйте,

Я просто столкнулся с самым удивительным поведением в компиляторе С#,

У меня есть следующий код:

Guid g1 = Guid.Empty;
bool b1= (g1 == null);

Ну, Guid не имеет значения NULL, поэтому он никогда не может быть равен null. сравнение, которое я делаю в строке 2 , всегда возвращает false.

Если вы делаете то же самое для целого числа, компилятор выдает предупреждение, говорящее, что результат всегда будет ложным:

int x=0;
bool b2= (x==null);

Мой вопрос: Почему компилятор позволяет сравнивать Guid с null?
По моим сведениям, он уже знает, что результат всегда неверен.
Является ли встроенное преобразование, выполненное таким образом, что компилятор принимает значение null, является возможным значением?
Я что-то пропустил здесь?

Спасибо

4b9b3361

Ответ 1

Значок правильный. Типы значений, которые определяют свои собственные операторы равенства, автоматически получают также отмененные версии, допускающие отмену. В этой ситуации применим нулевой оператор равенства, который принимает два нулевых указателя, будет вызываться и всегда будет возвращать false.

В С# 2 это вызвало предупреждение, но по какой-то причине это прекратило выдавать предупреждение для guid-to-null, но продолжает выдавать предупреждение для int-to-null. Я не знаю почему; У меня еще не было времени на расследование.

Извиняюсь за ошибку; Я, вероятно, испортил один из кодов кода обнаружения предупреждений при перезаписи нулевой логики на С# 3. Добавление деревьев выражений к языку существенно изменило порядок реализации нулевых арифметических операций; Я сделал множество ошибок, перемещая этот код. Это сложный код.

Ответ 2

Сравнение справедливо, потому что компилятор преобразует Guid в Nullable<Guid>, а затем имеет смысл.

Существует отчет об ошибке, предупреждающий об отсутствии предупреждения здесь.

См. здесь здесь для более полного объяснения Эрика Липперта.

Ответ 3

На самом деле существует случай, когда Guild == null вернет true.

Однако это трудно объяснить.

В структурах сопоставления ORM (например, openAccess), когда у вас есть поле Guid, которое будет иметь значение по умолчанию Guid.Empty, конечно, возможно иметь сценарий:

  • Вы добавляете новое поле Guid + свойство
  • Вы обновляете старую схему базы данных.. в этом случае все значения будут NULL в базе данных.
  • Если вы заполняете объект, имеющий этот нулевой столбец типа Гильдия, конечно, объект WILL получит значение Guid.Empty ОДНАКО, если вы используете запрос LINQ... в запросе LINQ выглядит, что Guid еще не заселен, поэтому вы необходимо использовать == null. Возможно, это ошибка, но так оно и есть.

Короче (используя OpenAccess, но, вероятно, не только):

var item = GetItems(). Где (i = > i.SomeGuidField == null); будет работать, и вы получите предметы с null guid это после обновления схемы. item.First(). SomeGuidField возвращает Empty Guid

var item = GetItems(). Где (i = > i.SomeGuidField == Guid.Empty); не будет работать, даже если после совокупности элемента это будет Guid.Empty и будет возвращать пустой результат.

Ответ 4

Конечно, это не только проблема для Guid. Такое же поведение наблюдается с любым типом struct, который не является предопределенным типом С# при условии, что struct перегружает operator == обычным способом. Другие примеры в рамках включают DateTime и TimeSpan.

Это заслуживает предупреждения о времени компиляции, поскольку, будучи технически законным из-за поднятого оператора, это не полезно, поскольку он всегда дает false. Таким образом, это указывает на ошибку программиста.

Как сказал Эрик Липперт в своем ответе, компилятор времени компиляции существовал вместе с компилятором Visual С# 2.0. В версиях с 3.0 по 5.0 предупреждение было случайно опущено (для этих "определяемых пользователем" struct типов, но не для заранее определенных типов значений, таких как int, а не для типов перечислений).

Так как С# 6.0 (на основе Roslyn), компилятор снова обнаруживает эту проблему кода. Однако из-за обратной совместимости (!) Предупреждение не выдается, если вы не скомпилируете свой код с так называемой строгой функцией.

Чтобы включить строгий режим, когда вы используете файл .csproj (в большинстве случаев), выгрузите проект из Visual Studio, отредактируйте файл, вставьте элемент XML:

<Features>strict</Features>

в каждый <PropertyGroup> (обычно будет больше одного) файла .csproj. Затем вы получаете предупреждение (может быть "продвинуто" до ошибки, если вы используете предупреждения "Предупреждение" как ошибки).

Если вы не можете редактировать .csproj, и если вы вызываете msbuild.exe из командной строки для компиляции, используйте переключатель:

/p:Features=strict

до msbuild.exe.

Если вы не используете файлы .csproj, потому что вы компилируете непосредственно с помощью csc.exe (компилятор С#), используйте переключатель:

/features:strict

до csc.exe в командной строке.