为什么 == 运算符适用于 Nullable什么时候 == 没有定义?

发布于 2024-12-29 01:50:43 字数 1490 浏览 3 评论 0原文

我只是在看 这个答案,其中包含来自 . NET Reflector,我注意到两件事:

  1. NullableT 时需要显式转换。
  2. == 运算符未定义。

考虑到这两个事实,令我惊讶的是它的编译结果:

int? value = 10;
Assert.IsTrue(value == 10);

使用代码 value == 10value 被神奇地转换为 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)。 = 不能应用于 CustomNullableint 类型的操作数”。

现在,无论修改多么微小,我都不希望能够做到......

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:

  1. An explicit conversion is required when going from Nullable<T> to T.
  2. 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

云朵有点甜 2025-01-05 01:50:43

考虑到这两个事实,我对它的编译感到惊讶

仅考虑到这两个事实,这就令人惊讶了。

这是第三个事实:在 C# 中,大多数运算符都“提升为可空”

通过“提升为可为空”,我的意思是,如果您说:

int? x = 1;
int? y = 2;
int? z = x + y;

那么您将得到“如果 x 或 y 为空,则 z 为空”的语义。如果两者都不为空,则添加它们的值,转换为可为空,并分配结果为 z。”

相等性也是如此,尽管相等性有点奇怪,因为在 C# 中,相等性仍然只是二值的。为了正确地提升,相等性应该是三值的:如果 x 或 y 为空,则 x == y 应该为 null;如果 x 和 y 都非空,则为 true 或 false。这就是它在 VB 中的工作原理,但在 C# 中却不然。

如果我的代码编写(几乎)相同,我希望我应该能够模仿 Nullable 的所有其他行为。

你将不得不学会忍受失望,因为你的期望与现实完全不符。 Nullable 是一种非常特殊的类型,其神奇的属性深深嵌入到 C# 语言和运行时中。例如:

  • C# 自动将运算符提升为可为空。没有办法说“自动将操作员提升到 MyNullable”。不过,通过编写自己的用户定义运算符,您可以非常接近。

  • C# 对 null 文字有特殊规则 - 您可以将它们分配给可为 null 的变量,并将它们与可为 null 的值进行比较,编译器会为它们生成特殊代码。

  • 可空值的装箱语义非常奇怪,并且已融入到运行时中。无法模拟它们。

  • isas 和合并运算符的可为空语义已融入语言中。

  • 可空值不满足struct 约束。无法模拟这一点。

  • 等等。

Given these two facts, it surprises me that this compiles

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:

int? x = 1;
int? y = 2;
int? z = x + y;

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#.

I would expect I should be able to mimic all the other behaviors of Nullable<T> if my code is written (almost) identically.

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.

满地尘埃落定 2025-01-05 01:50:43

好吧,如果您可以使用反射器,为什么不编译此代码:

int? value = 10;
Console.WriteLine(value == 10);

然后在反射器中打开它?您将看到这一点(确保选择“无”作为要反编译的 .net 版本):

int? value;
int? CS$0$0000;
&value = new int?(10);
CS$0$0000 = value;
Console.WriteLine((&CS$0$0000.GetValueOrDefault() != 10) ? 0 : &CS$0$0000.HasValue);

所以基本上编译器会为您完成繁重的工作。它理解与可为空值一起使用时“==”操作的含义,并相应地编译必要的检查。

Well, if you can use reflector why don't you compile this code:

int? value = 10;
Console.WriteLine(value == 10);

and then open it in reflector? You'll see this (make sure to select 'None' as .net version to decompile to):

int? value;
int? CS$0$0000;
&value = new int?(10);
CS$0$0000 = value;
Console.WriteLine((&CS$0$0000.GetValueOrDefault() != 10) ? 0 : &CS$0$0000.HasValue);

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.

十年九夏 2025-01-05 01:50:43

这是语言相关的。在处理可空值类型上的运算符时,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.

握住你手 2025-01-05 01:50:43

Nullable此方法

public static implicit operator T?(T value)
{
  return new T?(value);
}

看起来有一个从 10Nullable; 的隐式转换。 10

让 == / != 为您服务。您可以添加

public static bool operator ==(MyNullable<T> left, MyNullable<T> right) {}
// together with:
public static implicit operator MyNullable<T>(T value) {}

应该支持 myNullable == 10 操作

Nullable<T> has this method:

public static implicit operator T?(T value)
{
  return new T?(value);
}

It looks like there is an implicit conversion from it 10 to Nullable<int> 10

To make == / != work for you. You can add

public static bool operator ==(MyNullable<T> left, MyNullable<T> right) {}
// together with:
public static implicit operator MyNullable<T>(T value) {}

should give you support for myNullable == 10 operation

弃爱 2025-01-05 01:50:43

因为编译器 Nullable 转换为 Tthen 执行比较。

Because the compiler converts Nullable<T> to T and then performs the comparison.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文