为什么 TimeSpan 和 Guid Structs 可以与 null 进行比较?
我注意到一些 .NET 结构可以与 null 进行比较。 例如:
TimeSpan y = new TimeSpan();
if (y == null)
return;
将编译得很好(与 Guid 结构相同)。
现在我知道结构是值类型,并且上面的代码不应该编译,除非有一个接受对象的运算符 == 的重载。 但是,据我所知,没有。
我已经使用 Reflector 查看了该类,还查看了 MSDN 上的文档。
他们两个确实实现了以下接口:
IComparable, IComparable<T>, IEquatable<T>
但是,尝试实现相同的接口似乎没有帮助:
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。
有谁知道这是什么原因吗? 我只是想更好地理解。 这不是问题,因为我知道无论如何我都不应该将结构与 null 进行比较。
I've noticed that some .NET structs can be compared to null.
For example:
TimeSpan y = new TimeSpan();
if (y == null)
return;
will compile just fine (the same with the Guid struct).
Now I know that stucts are value type and that the code above should not compile, unless there's an overload of operator == which takes an object. But, as far as I could tell there isn't.
I've looked at the class with Reflector, and also at the docs on MSDN.
The two of them do implement the following interfaces:
IComparable, IComparable<T>, IEquatable<T>
but, trying to implment the same Interfaces did not seem to help:
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;
}
}
I'm using: .NET 2.0 Visual Studio 2005.
Does anyone has any idea what's the reason for this ?
I am just trying to get a better understanding. This isn't an issue as I know I shouldn't compare structs to null anyway.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这是
==
运算符。TimeSpan
类重载了相等运算符:这本身并不能与
null
进行比较,但是...随着可为空类型的到来,每个结构都可以隐式转换为其可为空类型,因此,当您看到类似
You don't see 的内容时,就表明这种情况正在发生:
Null 获取隐式转换(隐式赋值?),但是并非所有
System.Object
对象都会这样做:好的,但是相等运算符不接受可为 null 的参数,不是吗?
好吧, msdn 在这里有帮助,指出:
因此,您可以有效地免费为每个运算符获得可为空的实现,并具有固定的定义行为。 上面提到的“包含值”是不可空运算符返回的实际值。
It's the
==
operator.The
TimeSpan
class has an overload of the equality operator:This in itself doesn't make it possible to compare with
null
, but...With the arrival of nullable types, each struct is implicitly convertible to its nullable type, so when you see something like
You don't see that this is happening:
Null gets the implicit conversion (implicit assignment?), but not all
System.Object
objects do:Okay, but the equality operator doesn't take nullable arguments, does it?
Well, msdn is of help here, stating:
So you effectively get a nullable implementation for each operator for free, with a fixed defined behaviour. The "contained value" mentioned above is the actual value the non-nullable operator would return.
当包含可空类型时,这个问题就被有效地引入了。 存在从
TimeSpan
到TimeSpan?
的隐式转换,并且TimeSpan?
与该类型的 null 值之间存在比较。编译器对某些类型发出警告,这使得它想要做什么更清楚:
给出此警告:
我相信 Marc Gravell 和我计算出了一次发出警告的情况......遗憾的是它不一致。
This problem was effectively introduced when nullable types were included. There's an implicit conversion from
TimeSpan
toTimeSpan?
, and there's a comparison betweenTimeSpan?
and the null value of that type.The compiler issues a warning for some types which makes it clearer what it's trying to do:
Gives this warning:
I believe Marc Gravell and I worked out the circumstances under which the warning is given once... it's a shame it's not consistent.
C# 语言规范第 7.9.6 节中的泛型涵盖了这种情况。
我仔细研究了规范,但找不到更通用的规则。 乔恩的答案表明它是可为空的促销问题。
这条规则(或类似的变体)似乎确实适用于此。 如果您仔细查看反射的输出,您会发现不存在比较。 C# 编译器显然正在优化此比较并将其替换为 false。
例如,如果您输入以下内容
然后反编译它,您将看到以下内容
This case is covered for generics in section 7.9.6 of the C# language specification.
I dug through the spec for a bit and couldn't find a more general rule. Jon's answer indicates it's a nullable promotion issue.
This rule (or a similar variation) does seem to be being applied here. If you look at the reflected output closely you'll notice the comparison isn't there. The C# compiler is apparently optimizing this comparison away and replacing it with false.
For instance, if you type the following
Then decompile it you'll see the following
另请参阅:C# 3 (.NET 3.5) 版本的 csc 无法报告CS0162 表示无法访问的代码 (struct/null)
从 C# 3 编译器开始,这意味着它有时甚至不会警告您;-p
因为
Guid
/TimeSpan 等提供
==
,它们会落入这个陷阱,但不会警告您。See also: C# 3 (.NET 3.5) version of csc fails to report CS0162 for unrechable code (struct/null)
Starting with the C# 3 compiler that means it sometimes doesn't even warn you about this ;-p
Because
Guid
/TimeSpan
etc provide==
, they fall into this trap where it doesn't warn you.我找到了 :)
下面给出了一个警告:
编译器只是未能发出正确的警告,表明您键入的
null
已转换为TimeSpan 类型?< /code> 进行比较。
编辑:规范中的相关部分是第 §13.7.1 节,指出
null
可以隐式转换为任何可为空类型,并且(很难阅读)第 §13.7.2 节指出值类型 < code>T 可以隐式转换为T?
。我最初写的是:
无论发生什么,都是 C# 规范中的事情,因为像 JaredPar 所说的那样,它编译为简单的
false
。请注意,这不会编译:
I FOUND IT :)
The following gives a warning:
The compiler is just failing to emit the correct warning that the
null
you typed was converted to typeTimeSpan?
for the comparison.Edit: The related section in the spec is §13.7.1 stating that
null
can be implicitly converted to any nullable type, and (the very difficult to read) section §13.7.2 stating a value typeT
can be implicitly converted toT?
.What I originally wrote:
Whatever's happening is something in the C# spec because like JaredPar says it compiles to simply
false
.Note that this doesn't compile: