编译器不应允许 Guid == 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 是可能值的方式完成?
我在这里错过了什么吗?
The behaviour described below is specific to .net-3.5 only
I just ran across the most astonishing behavior in the C# compiler;
I have the following code:
Guid g1 = Guid.Empty;
bool b1= (g1 == null);
Well, Guid is not nullable therefore it can never be equal to null.
The comparison i'm making in line 2 always returns false.
If you make the same thing for an integer, the compiler issues an warning saying the result will always be false:
int x=0;
bool b2= (x==null);
My question is: Why does the compiler lets you compare a Guid to null?
According to my knowledge, it already knows the result is always false.
Is the built-in conversion done in such a way that the compiler does assume null is a possible value?
Am I missing anything here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
马克是正确的。定义自己的相等运算符的值类型也会自动免费定义可提升为空的版本。采用两个可空 guid 的可空相等运算符适用于这种情况,将被调用,并且始终返回 false。
在 C# 2 中,这会产生警告,但由于某种原因,这不再产生 guid-to-null 的警告,但继续产生 int-to-null 的警告。我不知道为什么;我还没有时间去调查。
我对这个错误表示歉意;在 C# 3 中重写可空逻辑时,我可能搞砸了警告检测代码路径之一。向语言添加表达式树主要改变了可空算术运算的实现顺序;我在移动该代码时犯了很多错误。这是一些复杂的代码。
Mark is correct. Value types that define their own equality operators automatically get lifted-to-nullable versions defined as well, for free. The nullable equality operator that takes two nullable guids is applicable in this situation, will be called, and will always return false.
In C# 2, this produced a warning, but for some reason, this stopped producing a warning for guid-to-null but continues to produce a warning for int-to-null. I don't know why; I haven't had time to investigate yet.
I apologize for the error; I probably screwed up one of the warning-detection code paths when rewriting the nullable logic in C# 3. The addition of expression trees to the language majorly changed the order in which nullable arithmetic operations are realized; I made numerous mistakes moving that code around. It's some complicated code.
该比较是有效的,因为编译器将
Guid
转换为Nullable
,然后它才有意义。有一个关于未发出警告的错误报告 这里。
请参阅
此处此处获取 Eric Lippert 的更完整解释。The comparison is valid because the compiler converts the
Guid
to aNullable<Guid>
and then it makes sense.There is a bug report on the warning not being issued here.
See
herehere for a fuller explanation from Eric Lippert.实际上有一种情况 Guild == null 将返回 true。
但这有点难以解释。
在 ORM 映射框架(例如 openAccess)中,当您有一个 Guid 字段,其默认值为 Guid.Empty 时,当然可能会出现以下情况:
简而言之(使用 OpenAccess 但可能不仅):
var item = GetItems().Where(i => i.SomeGuidField == null); 可以工作,并且 u将获得物品
对于 null guid,这是在架构更新之后。
item.First().SomeGuidField 将返回空 Guid
var item = GetItems().Where(i => i.SomeGuidField == Guid.Empty); 不会即使在填充项目后它将是 Guid.Empty 并将返回空结果,也可以工作。
Actually there is a case when Guild == null will return true.
However it is kinda hard to explain.
In ORM mapping frameworks (openAccess for example) when you have a Guid field which will have a default value of Guid.Empty of course it is possible to have the fallowing scenario :
In short (using OpenAccess but probably not only) :
var item = GetItems().Where(i => i.SomeGuidField == null); will work and u will get items
with null guid this is after an schema update.
item.First().SomeGuidField will return Empty Guid
var item = GetItems().Where(i => i.SomeGuidField == Guid.Empty); will not work even if after the population of the item it will be Guid.Empty and will return empty result.
当然,这不仅仅是
Guid
的问题。对于任何不是 C# 预定义类型的struct
类型,只要struct
重载了operator ==
通常的方式。该框架中的其他示例包括DateTime
和TimeSpan
。这值得编译时警告,因为虽然由于提升的运算符在技术上是合法的,但这不是一个有用的比较,因为它总是给出
false
。因此,这表明程序员犯了错误。正如 Eric Lippert 在他的回答中所说,Visual C# 2.0 编译器存在编译时警告。在版本 3.0 到 5.0 中,警告被意外忽略(对于这些“用户定义的”
struct
类型,但不适用于像int
这样的预定义值类型,也不适用于枚举类型)。从 C# 6.0(基于 Roslyn)开始,编译器再次检测到此代码问题。但是,由于向后兼容性(?!),除非您使用所谓的严格功能编译代码,否则不会发出警告。
要在使用
.csproj
文件(最常见的情况)时启用严格,请从 Visual Studio 卸载项目,编辑文件,将 XML 元素插入到每个
.csproj
文件的 code> (通常会有多个)。然后您会收到警告(如果您使用“将警告视为错误”,则可以“升级”为错误)。如果您无法编辑
.csproj
并且从命令行调用msbuild.exe
进行编译,请使用 switch:到
msbuild.exe
。如果您不使用
.csproj
文件,因为您直接使用csc.exe
(C# 编译器)进行编译,请使用开关:到
csc.exe
在命令行上。Of course this is not only an issue for
Guid
. The same behavior is seen with anystruct
type which is not a pre-defined type of C# provided that thestruct
overloadsoperator ==
in the usual way. Other examples in the framework includeDateTime
andTimeSpan
.This deserves a compile-time warning since, while technically legal because of the lifted operator, this is not a useful comparison since it always gives
false
. As such, it is an indication of a programmer mistake.As Eric Lippert said in his answer, the compile-time warning existed with the Visual C# 2.0 compiler. In versions 3.0 through 5.0, the warning was accidentally omitted (for these "user-defined"
struct
types, but not for pre-defined value types likeint
, and not for enum types).Since C# 6.0 (based on Roslyn), the compiler detects this code problem once again. However, because of backwards compatibility(?!), the warning is not issued unless you compile your code with the so-called strict feature.
To enable strict when you use a
.csproj
file (most usual case), unload the project from Visual Studio, edit the file, insert the XML element:into each
<PropertyGroup>
(there will usually be more than one) of the.csproj
file. You then get the warning (can be "promoted" to an error if you use Treat warnings as errors).If you cannot edit the
.csproj
and if you callmsbuild.exe
from the command line for compiling, use the switch:to
msbuild.exe
.If you do not use
.csproj
files because you compile directly withcsc.exe
(the C# compiler), use the switch:to
csc.exe
on the command line.