下面描述的行为仅针对.net-3.5
我刚刚遇到了C#编译器中最令人惊讶的行为;
我有以下代码:
Guid g1 = Guid.Empty;
bool b1= (g1 == null);
嗯, Guid不可为空,因此永远不能等于null 。 我在第2行中进行的比较始终返回false 。
如果对整数做同样的事情,编译器会发出警告,说结果总是为假:
int x=0;
bool b2= (x==null);
我的问题是:为什么编译器允许您将Guid与null进行比较?
据我所知,它已经知道结果总是错误的
内置转换是否以编译器假定null为可能值的方式完成?
我在这里错过了什么吗?
答案 0 :(得分:81)
马克是对的。定义自己的相等运算符的值类型自动获得定义的可升级版本,免费。采用两个可空guid的可空等式运算符适用于这种情况,将被调用,并且将始终返回false。
在C#2中,这会产生一个警告,但由于某种原因,这会停止为guid-to-null发出警告,但会继续产生int-to-null的警告。我不知道为什么;我还没来得及调查。
我为错误道歉;在重写C#3中的可空逻辑时,我可能搞砸了一个警告检测代码路径。在语言中添加表达式树主要改变了可空算术运算的实现顺序;我犯了许多错误移动代码。这是一些复杂的代码。
答案 1 :(得分:13)
答案 2 :(得分:1)
实际上,当Guild == null将返回true时会出现情况。
但是有点难以解释。
在ORM映射框架(例如openAccess)中,如果你有一个Guid字段,其默认值为Guid.Empty,当然可以有以下情况:
简而言之(使用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并将返回空结果。
答案 3 :(得分:0)
当然,这不仅是Guid
的问题。任何struct
类型都会出现相同的行为,这种类型不是预定义的C#类型,前提是struct
以通常的方式重载operator ==
。框架中的其他示例包括DateTime
和TimeSpan
。
这值得编译时警告,因为虽然技术上合法,因为提升的运算符,这不是一个有用的比较,因为它总是给出false
。因此,它表明了程序员的错误。
正如Eric Lippert在他的回答中所说,编译时警告存在于Visual C#2.0编译器中。在版本3.0到5.0中,意外省略了警告(对于这些“用户定义的”struct
类型,但不是针对int
等预定义值类型,而不是针对枚举类型。
自C#6.0(基于Roslyn)以来,编译器再次检测到此代码问题。但是,由于向后兼容性(?!),除非使用所谓的严格功能编译代码,否则不会发出警告。
要在使用.csproj
文件时启用strict(最常见的情况),请从Visual Studio卸载项目,编辑文件,插入XML元素:
<Features>strict</Features>
到<PropertyGroup>
文件的每个.csproj
(通常会有一个以上)。然后,您会收到警告(如果您将处理警告用作错误,则可以“提升”为错误。)
如果您无法编辑.csproj
,并且从命令行调用msbuild.exe
进行编译,请使用开关:
/p:Features=strict
到msbuild.exe
。
如果因为使用.csproj
(C#编译器)直接编译而不使用csc.exe
文件,请使用开关:
/features:strict
命令行上的csc.exe
。