为什么比较 DateTime 和 null 时没有编译器警告?

use*_*392 0 c# compiler-warnings visual-studio .net-core

Visual Studio 显示编译器警告CS04721,其中(int)5 == null读取

表达式的结果始终为“false”,因为“int”类型的值永远不等于“int”类型的“null”?

bool x = (int)5 == null;
Run Code Online (Sandbox Code Playgroud)

DateTime但是,如果使用对象,则不会发出警告。

bool y = DateTime.UtcNow == null;
Run Code Online (Sandbox Code Playgroud)

由于DateTimeis not Nullable<DateTime>,因此它永远不可能为 null 。第二个语句没有显示类似警告的原因是什么?

Nin*_*rry 7

代码

bool x = (int)5 == null;
Run Code Online (Sandbox Code Playgroud)

CS0472生成自 C# 第一个版本以来就存在的警告号。

代码

bool y = DateTime.UtcNow == null;
Run Code Online (Sandbox Code Playgroud)

产生警告编号CS8073。根据其帮助页面,该警告CS8073是“警告波 5”的一部分,仅在 C# 版本 9 中引入。

因此,在使用 C# 9 或更高版本时您会看到警告,而在使用旧版本时则不会看到它。

您是否看到警告也会受到您在项目的项目选项中配置的“AnalysisLevel”的影响。要查看 warning CS8073,您应该启用警告级别 5 或更高级别。

警告CS8073特别适用于结构类型,而较旧的警告则处理内置原始值类型。


Microsoft发布了一篇博客文章,宣布引入新警告。根据该博客文章,CS8073引入警告是因为它处理“常见的编码错误”。


为什么警告没有更早实施只能猜测。我的猜测如下:

第一个示例中与类型的比较运算符int内置于语言中,而第二个示例中的相等运算符是类中的运算符重载,在.net Framework 源代码DateTime中作为 C# 代码实现。

因此,为了在第二种情况下生成警告,编译器必须查看结构类型的实际实现及其可用的运算符重载。

事实上,可能存在允许对结构类型和不同引用类型使用相等运算符的重载,在这种情况下,警告将不合理,因为与 的比较null可能会返回true

struct type与 的比较null将返回的程序示例true(禁用 Nullable 选项):

internal class Program
{
    public struct X
    {
        public static bool operator ==(X s1, object s2) => s1.Equals(s2);
        public static bool operator !=(X s1, object s2) => s1.Equals(s2);
        public override bool Equals(object other) => true;
        public override int GetHashCode() => 0;
    }

    static void Main()
    {
        X x = new X();
        bool b = x == null;
        Console.WriteLine(b);
    }
}
Run Code Online (Sandbox Code Playgroud)