为什么TimeSpan和Guid Structs可以比较为null?

dtr*_*roy 18 .net c# null struct .net-2.0

我注意到一些.NET结构可以与null进行比较.例如:

  TimeSpan y = new TimeSpan();
        if (y == null)
            return;
Run Code Online (Sandbox Code Playgroud)

将编译得很好(与Guid结构相同).
现在我知道stucts是值类型,并且上面的代码不应该编译,除非有一个带有对象的operator ==的重载.但是,据我所知,没有.
我用Reflector和MSDN上的文档查看了这个类.
他们两个确实实现了以下接口:

IComparable, IComparable<T>, IEquatable<T>
Run Code Online (Sandbox Code Playgroud)

但是,尝试使用相同的接口似乎没有帮助:

struct XX : IComparable, IComparable<XX>, IEquatable<XX> {
    public int CompareTo(Object obj) {
        return 0;
    }
    public int CompareTo (XX other){
        return 0;
    }
    public bool Equals (XX other){
        return false;
    }
    public override bool Equals(object value){
        return false;
    }
    public static int Compare(XX t1, XX t2){
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在使用:.NET 2.0 Visual Studio 2005.

有谁知道这是什么原因?我只是想更好地理解.这不是问题,因为我知道我不应该将结构与null进行比较.

Ken*_* K. 14

这是==运营商.

TimeSpan班有平等的运营商的重载:

public static bool operator ==(DateTime d1, DateTime d2)
{
     return (t1._ticks == t2._ticks);
}
Run Code Online (Sandbox Code Playgroud)

这本身不能与之比较null, ......

随着可空类型的到来,每个结构都可以隐式转换为可为空的类型,所以当你看到类似的东西时

TimeSpan y = new TimeSpan();
if (y == null)
    return;
Run Code Online (Sandbox Code Playgroud)

没有看到这种情况发生了:

TimeSpan y = new TimeSpan();
if ((Nullable<TimeSpan>)y == (Nullable<TimeSpan>)null)
    return;
Run Code Online (Sandbox Code Playgroud)

Null获取隐式转换(隐式赋值?),但并非所有System.Object对象都执行:

TimeSpan y = new TimeSpan();
object o = null;
if (y == o) //compiler error
    return;
Run Code Online (Sandbox Code Playgroud)

好的,但是相等运算符不会采用可为空的参数,是吗?

好吧,msdn在这里有所帮助,说明:

预定义的一元和二元运算符以及值类型存在的任何用户定义的运算符也可以由可空类型使用.如果[任何]操作数为null,则这些运算符产生空值; 否则,运算符使用包含的值来计算结果.

因此,您可以免费获得每个运算符的可空实现,并具有固定的定义行为.上面提到的"包含值"是非可空运算符返回的实际值.


Jar*_*Par 7

在C#语言规范的第7.9.6节中,这种情况适用于泛型.

即使T可以表示值类型,也允许使用x == null结构,并且当T是值类型时,结果简单地定义为false.

我挖了一下这个规范,但找不到更一般的规则.乔恩的回答表明这是一个可以为空的促销问题.

这个规则(或类似的变化)似乎确实在这里应用.如果仔细观察反射输出,你会发现比较不存在.C#编译器显然正在优化这种比较并将其替换为false.

例如,如果键入以下内容

var x = new TimeSpan();
var y = x == null;
Console.WriteLine(x);
Run Code Online (Sandbox Code Playgroud)

然后反编译你会看到以下内容

var x = new TimeSpan();
var y = false;
Console.WriteLine(x);
Run Code Online (Sandbox Code Playgroud)

  • 实际上,如果它取代了比较,编译器应该在这里发出警告.至少,它确实在其他情况下.神秘. (2认同)

Jon*_*eet 7

当包含可空类型时,有效地引入了这个问题.这里有一个隐式转换从TimeSpanTimeSpan?,而且也之间的比较TimeSpan?以及该类型的空值.

编译器会针对某些类型发出警告,这使得它更清楚它正在尝试执行的操作:

int x = 10;
if (x == null)
{
    Console.WriteLine();
}
Run Code Online (Sandbox Code Playgroud)

给出这个警告:

Test.cs(9,13): warning CS0472: The result of the expression is always 'false'
       since a value of type 'int' is never equal to 'null' of type 'int?'
Run Code Online (Sandbox Code Playgroud)

我相信Marc Gravell和我一起制定了警告的情况......这是一种耻辱,这是不一致的.