编译器不应允许 Guid == null

发布于 2024-08-19 17:05:14 字数 544 浏览 4 评论 0原文

下面描述的行为仅特定于 .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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

分开我的手 2024-08-26 17:05:14

马克是正确的。定义自己的相等运算符的值类型也会自动免费定义可提升为空的版本。采用两个可空 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.

小…红帽 2024-08-26 17:05:14

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

有一个关于未发出警告的错误报告 这里

请参阅此处 此处获取 Eric Lippert 的更完整解释。

The comparison is valid because the compiler converts the Guid to a Nullable<Guid> and then it makes sense.

There is a bug report on the warning not being issued here.

See here here for a fuller explanation from Eric Lippert.

桃扇骨 2024-08-26 17:05:14

实际上有一种情况 Guild == null 将返回 true。

但这有点难以解释。

在 ORM 映射框架(例如 openAccess)中,当您有一个 Guid 字段,其默认值为 Guid.Empty 时,当然可能会出现以下情况:

  • 您添加一个新的 Guid 字段 + 一个属性
  • 您升级旧数据库schema.. 在这种情况下,数据库中的所有值都将为 NULL。
  • 如果您填充具有 Guild 类型的空列的对象,当然该对象将获得 Guid.Empty 值,但是如果您使用 LINQ 查询...在 LINQ 查询中,它看起来 Guid 尚未填充,因此您需要使用== 空。也许这是一个错误,但事实就是如此。

简而言之(使用 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 :

  • You add a new Guid field + a Property
  • You upgrade the old database schema.. in this case all values will be NULL in the database.
  • If you populate an object having this null column of type Guild of course the Object WILL get an Guid.Empty value HOWEVER if you use an LINQ query ... in the LINQ query it looks the Guid is not yet populated so you need to use == null. Maybe it is a bug but this is the way it is.

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.

我不是你的备胎 2024-08-26 17:05:14

当然,这不仅仅是 Guid 的问题。对于任何不是 C# 预定义类型的 struct 类型,只要 struct 重载了 operator ==通常的方式。该框架中的其他示例包括 DateTimeTimeSpan

这值得编译时警告,因为虽然由于提升的运算符在技术上是合法的,但这不是一个有用的比较,因为它总是给出 false。因此,这表明程序员犯了错误。

正如 Eric Lippert 在他的回答中所说,Visual C# 2.0 编译器存在编译时警告。在版本 3.0 到 5.0 中,警告被意外忽略(对于这些“用户定义的”struct 类型,但不适用于像 int 这样的预定义值类型,也不适用于枚举类型)。

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

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

<Features>strict</Features>

到每个 .csproj 文件的 code> (通常会有多个)。然后您会收到警告(如果您使用“将警告视为错误”,则可以“升级”为错误)。

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

/p:Features=strict

msbuild.exe

如果您不使用 .csproj 文件,因为您直接使用 csc.exe(C# 编译器)进行编译,请使用开关:

/features:strict

csc.exe 在命令行上。

Of course this is not only an issue for Guid. The same behavior is seen with any struct type which is not a pre-defined type of C# provided that the struct overloads operator == in the usual way. Other examples in the framework include DateTime and TimeSpan.

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 like int, 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:

<Features>strict</Features>

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 call msbuild.exe from the command line for compiling, use the switch:

/p:Features=strict

to msbuild.exe.

If you do not use .csproj files because you compile directly with csc.exe (the C# compiler), use the switch:

/features:strict

to csc.exe on the command line.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文