为什么时间跨度以及将GUID结构进行比较,以空?(Why can TimeSpan and Guid

2019-06-27 18:44发布

我注意到,一些.NET结构可以比作空。 例如:

  TimeSpan y = new TimeSpan();
        if (y == null)
            return;

将编译就好了(用GUID结构相同)。
现在我知道,stucts是值类型和上面的代码不应该编译,除非有运营商的重载==这需要一个对象。 但是,据我所知没有。
我看与反射器类,并在MSDN上的文档。
他们俩做实现以下接口:

IComparable, IComparable<T>, IEquatable<T>

但是,试图implment相同的接口似乎并没有帮助:

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;
    }
}

我使用:.NET 2.0的Visual Studio 2005。

有没有人有任何想法是这个原因? 我只是想获得更好的理解。 这不是一个问题,因为我知道我不应该比较结构反正空。

Answer 1:

这是==操作符。

TimeSpan类具有平等运营商的重载:

public static bool operator ==(DateTime d1, DateTime d2)
{
     return (t1._ticks == t2._ticks);
}

这本身并没有使人们有可能以比较null ...

随着可空类型的到来, 每一个结构是隐式转换到其可空类型 ,所以当你看到喜欢的东西

TimeSpan y = new TimeSpan();
if (y == null)
    return;

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

TimeSpan y = new TimeSpan();
if ((Nullable<TimeSpan>)y == (Nullable<TimeSpan>)null)
    return;

空变隐式转换,但不是所有 (隐式分配?) System.Object对象做:

TimeSpan y = new TimeSpan();
object o = null;
if (y == o) //compiler error
    return;

好吧,但平等的运营商不采取为空的参数,不是吗?

那么, MSDN是帮助在这里,他说:

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

所以,你得到有效的每个操作员可为空实施免费的 ,具有固定定义的行为。 上面提到的“包含的价值”是实际值的非空的运营商将返回。



Answer 2:

当被列入可空类型被有效地引入此问题。 这里有一个隐式转换,从TimeSpanTimeSpan? ,并有之间的比较TimeSpan? 以及该类型的空值。

编译器会发出某些类型的警告,这使得它更清楚什么它试图做:

int x = 10;
if (x == null)
{
    Console.WriteLine();
}

给出了这样的警告:

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?'

我相信马克Gravell我制定了在其下一次给予警告的情况下......这是一个耻辱它不是一致的。



Answer 3:

这种情况下,覆盖在C#语言规范的第7.9.6仿制药。

在x == NULL构建体允许即使Ť可以表示的值的类型,并且将结果简单地定义为假当T是一个值类型。

我通过规范的位挖,不能找到一个更一般的规则。 乔恩的回答表明它是一个可空的推广问题。

这条规则(或类似的变化)似乎要被应用于此。 如果你看一下反射输出观察,你会发现比较是不存在的。 C#编译器显然是优化这种比较远,并以虚假的取代它。

例如,如果您键入以下

var x = new TimeSpan();
var y = x == null;
Console.WriteLine(x);

然后反编译它,你会看到下面的

var x = new TimeSpan();
var y = false;
Console.WriteLine(x);


Answer 4:

另请参阅: C#3(.NET 3.5)CSC的版本没有报告CS0162为unrechable代码(结构/空)

与C#编译器3,这意味着它有时甚至不发出警告,;-p开始

由于Guid / TimeSpan等提供== ,他们落入这个陷阱在它不发出警告。



Answer 5:

我发现它 :)

下面给出了一个警告:

int i = 0;
if (i == null)
// ^^ Warning: The result of the expression is always 'false' since a value of
//             type 'int' is never equal to 'null' of type 'int?'

编译器只是无法发出正确的警告, null键入被转换为类型TimeSpan? 用于比较。

编辑:在规范中的相关章节是§13.7.1指出null可以隐式转换到任何可空类型,和(非常难读)部分§13.7.2声明值类型T可以隐式转换到T?

我原来写:

不管发生的是什么东西在C#规范,因为像JaredPar说,它编译成简单的false

请注意,这并不编译:

TimeSpan ts = new TimeSpan();
object o = null;
if (ts == o) // error, Operator '==' cannot be applied to operands of type 'System.TimeSpan' and 'object'
    ...


文章来源: Why can TimeSpan and Guid Structs be compared to null?