【问题标题】:Guid == null should not be allowed by the compiler编译器不应允许 Guid == null
【发布时间】:2011-01-11 18:44:03
【问题描述】:

下面描述的行为仅特定于 .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 是可能值的方式完成?
我在这里有什么遗漏吗?

【问题讨论】:

  • 它实际上不是重复的。 Luis 的问题是关于为什么编译器在将结构与 null 进行比较时不发出警告,而在比较值类型时却发出警告。
  • 我不同意这是重复的......
  • 我不认为这是重复的

标签: c# .net .net-3.5 guid


【解决方案1】:

马克是正确的。定义自己的相等运算符的值类型也会自动免费获得定义的提升为可空的版本。采用两个可空 guid 的可空相等运算符适用于这种情况,将被调用,并且始终返回 false。

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

我为这个错误道歉;在 C# 3 中重写可空逻辑时,我可能搞砸了一条警告检测代码路径。向语言中添加表达式树主要改变了实现可空算术运算的顺序。我在移动该代码时犯了许多错误。这是一些复杂的代码。

【讨论】:

  • @Chris,我今天早上还没有任何饮食 Dr. Pepper,所以我有点慢。我无法理解你在问什么。你在问为什么字符串是引用类型而 guid 是值类型?
  • 是的,我相信字符串的行为方式应该与 Guid 完全相同。它们是不可变的,但仍然可以定义为 null 的事实使它们成为一种伪原始类型,需要大量的自定义编码来处理它们,这一点很明显,当 String.IsNullOrEmptyString.Empty 这样的方法存在时就会这样。
  • 你一定会喜欢 StackOverflow。你还能在哪里提出一个主要框架的问题,然后作者回来说哎呀。
  • 我刚刚用C#4.0测试过,问题依旧
  • @Eric:刚记得用 c#4.5 测试过,但问题仍然存在……可能在 5.0 中……
【解决方案2】:

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

有一个关于未发出警告here 的错误报告。

请参阅 here here 以获得 Eric Lippert 的更全面解释。

【讨论】:

  • 对不起,这没有意义。为什么它不自动将 int 转换为 Nullable
【解决方案3】:

其实有一种Guild == null 会返回true的情况。

但是这有点难以解释。

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

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

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

var item = GetItems().Where(i => i.SomeGuidField == null); 会起作用,你会得到物品 使用 null guid,这是在模式更新之后。 item.First().SomeGuidField 将返回 Empty Guid

var item = GetItems().Where(i => i.SomeGuidField == Guid.Empty); 将不起作用,即使在填充项目之后它将是 Guid.Empty 并且将返回空结果。

【讨论】:

  • 这实际上并不是Guid == null 返回true;这是一个查询引擎,它解释表达式树的方式与 C# 不同。
【解决方案4】:

当然,这不仅仅是Guid 的问题。如果struct 以通常的方式重载operator ==,则任何struct 类型都可以看到相同的行为,该类型不是C# 的预定义类型。框架中的其他示例包括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 文件的每个&lt;PropertyGroup&gt;(通常不止一个)。然后您会收到警告(如果您使用将警告视为错误,则可以“升级”为错误)。

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

/p:Features=strict

msbuild.exe

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

/features:strict

csc.exe 在命令行。

【讨论】:

    猜你喜欢
    • 2010-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多