Guid == null不应该被编译器允许

可能重复:
C#好的比较值types为null

下面描述的行为仅限于.net-3.5

你好,

我只是遇到了C#编译器中最令人惊讶的行为。

我有以下代码:

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

那么, Guid是不可空的,因此它不能等于null 。 我在第2行做的比较 总是返回false

如果你对一个整数做同样的事情,编译器会发出一个警告,说明结果总是为false:

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

我的问题是: 为什么编译器让你比较一个Guid为null
据我所知,它已经知道结果总是假的。
内置的转换是以这样一种方式完成的,即编译器假定null是一个可能的值?
我在这里错过了什么?

谢谢

马克是正确的。 定义它们自己的相等运算符的值types也自动地被提升为可空的版本。 在这种情况下,可以使用两个可以为空的guid的可为null的相等运算符将被调用,并且总是返回false。

在C#2中,这产生了一个警告,但由于某种原因,这停止了产生guid-null的警告,但继续产生int-to-null的警告。 我不知道为什么; 我还没有时间调查。

我对这个错误表示歉意。 当重写C#3中的可空逻辑时,我可能搞错了其中一个警告检测代码path。expression式树添加到语言中,主要改变了可空算术运算的顺序; 我在移动代码时犯了许多错误。 这是一些复杂的代码。

该比较是有效的,因为编译器将Guid转换为Nullable<Guid>然后才有意义。

有没有在这里发布警告的错误报告。

这里看到从Eric Lippert更全面的解释。

事实上,Guild == null会返回true。

然而,这是很难解释。

在ORM映射框架(例如openAccess)中,当你有一个Guid字段时,它的默认值是Guid.Empty,当然可以有这个hibernate的场景:

  • 您添加一个新的Guid字段+一个属性
  • 您升级旧的数据库模式..在这种情况下,数据库中的所有值将为NULL。
  • 如果你填充一个对象具有这种types为Guild的空列,当然对象会得到一个Guid.Empty值但是,如果你在LINQ查询中使用LINQ查询,那么它看起来Guid还没有被填充,所以你需要使用== null。 也许这是一个错误,但这是事实。

简而言之( 使用OpenAccess但可能不仅 ):

var item = GetItems()。Where(i => i.SomeGuidField == null); 将工作,你会得到与空guid的项目,这是模式更新后。 item.First()。SomeGuidField将返回空的Guid

var item = GetItems()。其中​​(i => i.SomeGuidField == Guid.Empty); 将不会工作,即使在项目的人口后它将Guid.Empty,并将返回空的结果。

当然,这不仅是Guid一个问题。 对于任何不是预定义types的C#的structtypes,只要structoperator ==按照通常的方式,就可以看到相同的行为。 框架中的其他示例包括DateTimeTimeSpan

这是值得的编译时间警告,因为虽然在技术上是合法的,因为操作员被解除,但这不是一个有用的比较,因为它总是false 。 因此,这是程序员错误的performance。

正如Eric Lippert在他的回答中所说,编译时警告存在于Visual C#2.0编译器中。 在版本3.0到5.0中,警告被意外地省略(对于这些“用户定义的” structtypes,但对于预定义的值types如int而不是对于枚举types)。

由于C#6.0(基于Roslyn),编译器再次检测到这个代码问题。 但是,由于向后兼容性(?!),除非使用所谓的严格特性编译代码,否则不会发出警告。

要在使用.csproj文件(最常见的情况)时启用strict,请从Visual Studio中卸载项目,编辑文件,插入XML元素:

 <Features>strict</Features> 

到每个<PropertyGroup> (通常会有多个) .csproj文件。 然后,您会收到警告(如果您使用“处理”警告作为错误,则可以“提升”为错误)。

如果您不能编辑.csproj并且如果从命令行调用msbuild.exe进行编译,请使用switch:

 /p:Features=strict 

msbuild.exe

如果因为使用csc.exe (C#编译器)直接编译而不使用.csproj文件,请使用switch:

 /features:strict 

到命令行上的csc.exe