为什么 == 运算符适用于 Nullable什么时候 == 没有定义?
我只是在看 这个答案,其中包含来自 . NET Reflector,我注意到两件事:
- 从
Nullable
到T
时需要显式转换。 ==
运算符未定义。
考虑到这两个事实,令我惊讶的是它的编译结果:
int? value = 10;
Assert.IsTrue(value == 10);
使用代码 value == 10
,value
被神奇地转换为 int
(因此允许使用 int
的 ==
运算符,或者为 Nullable
.(或者,我认为不太可能,Reflector 遗漏了一些代码。)==
运算符;
我希望必须执行以下操作之一:
Assert.IsTrue((value.Equals(10)); // works because Equals *is* defined
Assert.IsTrue(value.Value == 10); // works because == is defined for int
Assert.IsTrue((int?)value == 10); // works because of the explicit conversion
这些当然可以工作,但是 ==
也可以工作,而这就是我不做的部分 我注意到
这一点并提出这个问题的原因是我正在尝试编写一个与 Nullable
类似的结构,我从上面链接的 Reflector 代码开始,并且不幸的是,我只是做了一些非常小的修改。 CustomNullable
的工作方式不同。我无法执行 Assert.IsTrue(value == 10)
。 = 不能应用于 CustomNullable
和 int
类型的操作数”。
现在,无论修改多么微小,我都不希望能够做到......
CustomNullable<T> value = null;
因为我知道 Nullable
背后有一些编译器魔法,允许值是设置为 null
即使 Nullable
是一个结构,但我希望我应该能够模仿Nullable
如果我的代码编写(几乎)相同。
任何人都可以阐明 Nullable
的各种运算符在未定义时如何工作吗?
I was just looking at this answer, which contains the code for Nullable<T>
from .NET Reflector, and I noticed two things:
- An explicit conversion is required when going from
Nullable<T>
toT
. - The
==
operator is not defined.
Given these two facts, it surprises me that this compiles:
int? value = 10;
Assert.IsTrue(value == 10);
With the code value == 10
, either value
is being magically converted to an int
(hence allowing int
's ==
operator to be used, or the ==
operator is being magically defined for Nullable<int>
. (Or, I presume less likely, Reflector is leaving out some of the code.)
I would expect to have to do one of the following:
Assert.IsTrue((value.Equals(10)); // works because Equals *is* defined
Assert.IsTrue(value.Value == 10); // works because == is defined for int
Assert.IsTrue((int?)value == 10); // works because of the explicit conversion
These of course work, but ==
also works, and that's the part I don't get.
The reason I noticed this and am asking this question is that I'm trying to write a struct that works somewhat similarly to Nullable<T>
. I began with the Reflector code linked above, and just made some very minor modifications. Unfortunately, my CustomNullable<T>
doesn't work the same way. I am not able to do Assert.IsTrue(value == 10)
. I get "Operator ==
cannot be applied to operands of type CustomNullable<int>
and int
".
Now, no matter how minor the modification, I would not expect to be able to do...
CustomNullable<T> value = null;
...because I understand that there is some compiler magic behind Nullable<T>
that allows values to be set to null
even though Nullable<T>
is a struct, but I would expect I should be able to mimic all the other behaviors of Nullable<T>
if my code is written (almost) identically.
Can anyone shed light on how the various operators of Nullable<T>
work when they appear not to be defined?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
仅考虑到这两个事实,这就令人惊讶了。
这是第三个事实:在 C# 中,大多数运算符都“提升为可空”。
通过“提升为可为空”,我的意思是,如果您说:
那么您将得到“如果 x 或 y 为空,则 z 为空”的语义。如果两者都不为空,则添加它们的值,转换为可为空,并分配结果为 z。”
相等性也是如此,尽管相等性有点奇怪,因为在 C# 中,相等性仍然只是二值的。为了正确地提升,相等性应该是三值的:如果 x 或 y 为空,则 x == y 应该为 null;如果 x 和 y 都非空,则为 true 或 false。这就是它在 VB 中的工作原理,但在 C# 中却不然。
你将不得不学会忍受失望,因为你的期望与现实完全不符。
Nullable
是一种非常特殊的类型,其神奇的属性深深嵌入到 C# 语言和运行时中。例如:C# 自动将运算符提升为可为空。没有办法说“自动将操作员提升到 MyNullable”。不过,通过编写自己的用户定义运算符,您可以非常接近。
C# 对 null 文字有特殊规则 - 您可以将它们分配给可为 null 的变量,并将它们与可为 null 的值进行比较,编译器会为它们生成特殊代码。
可空值的装箱语义非常奇怪,并且已融入到运行时中。无法模拟它们。
is
、as
和合并运算符的可为空语义已融入语言中。可空值不满足
struct
约束。无法模拟这一点。等等。
Given only those two facts, that is surprising.
Here's a third fact: in C#, most operators are 'lifted to nullable'.
By "lifted to nullable", I mean that if you say:
then you get the semantics of "if either x or y is null then z is null. If both are not null then add their values, convert to nullable, and assign the result to z."
The same goes for equality, though equality is a bit weird because in C#, equality is still only two-valued. To be properly lifted, equality ought to be three-valued: x == y should be null if either x or y is null, and true or false if x and y are both non-null. That's how it works in VB, but not in C#.
You are going to have to learn to live with disappointment because your expectation is completely out of line with reality.
Nullable<T>
is a very special type and its magical properties are embedded deeply within the C# language and the runtime. For example:C# automatically lifts operators to nullable. There's no way to say "automatically lift operators to MyNullable". You can get pretty close by writing your own user-defined operators though.
C# has special rules for null literals -- you can assign them to nullable variables, and compare them to nullable values, and the compiler generates special code for them.
The boxing semantics of nullables are deeply weird and baked into the runtime. There is no way to emulate them.
Nullable semantics for the
is
,as
and coalescing operators are baked in to the language.Nullables do not satisfy the
struct
constraint. There is no way to emulate that.And so on.
好吧,如果您可以使用反射器,为什么不编译此代码:
然后在反射器中打开它?您将看到这一点(确保选择“无”作为要反编译的 .net 版本):
所以基本上编译器会为您完成繁重的工作。它理解与可为空值一起使用时“==”操作的含义,并相应地编译必要的检查。
Well, if you can use reflector why don't you compile this code:
and then open it in reflector? You'll see this (make sure to select 'None' as .net version to decompile to):
So basically the compiler does the heavy lifting for you. It understands what '==' operation means when used with nullables and compiles the necessary checks accordingly.
这是语言相关的。在处理可空值类型上的运算符时,C# 和 Visual Basic 会发出不同的代码。要理解它,您需要查看实际的 IL 代码。
This is language dependent. C# and Visual Basic emit different code when dealing with operators on nullable value types. To udnerstand it you need to look at the actual IL code.
Nullable
有此方法:看起来有一个从
10
到Nullable; 的隐式转换。 10
让 == / != 为您服务。您可以添加
应该支持
myNullable == 10
操作Nullable<T>
has this method:It looks like there is an implicit conversion from it
10
toNullable<int> 10
To make == / != work for you. You can add
should give you support for
myNullable == 10
operation因为编译器 将
Nullable
转换为T
和 then 执行比较。Because the compiler converts
Nullable<T>
toT
and then performs the comparison.