为什么Nullable<T>不会重载==运算符?

c#

Nullable<Int32> x = 5;
Nullable<Int32> y = 10;

if (x == y) {
   ...
}

根据我的理解,上面的代码将同时转换xand ytoObject然后 useObjectpublic static bool Equals(Object objA, Object objB)方法

如果我的理解是正确的,那么为什么不重载 == 和 != 运算符为Nullable<T>

public struct Nullable<T> where T : struct {
   ...
   public static bool operator == (Nullable<T> a, Nullable<T> b) {
      ...// do some nesseary null check
      return value.Equals(other);
   }
}

那么我们可以保存两个铸件吗?

回答

可空值类型的运算符在语言规范中实际上是“硬编码”的。他们被称为Lifted Operators。

提升运算符允许对不可为空的值类型进行操作的预定义和用户定义的运算符也可以与这些类型的可为空形式一起使用。

对于等式运算符,

提升形式是通过向?每个操作数类型添加一个修饰符来构造的。提升运算符认为两个空值相等,空值不等于任何非空值。如果两个操作数都不为空,则提升的运算符解开操作数并应用基础运算符以生成 bool 结果。

这是在语言规范中指定的,因此所有运算符都由“编译器魔术”实现,这就是为什么您在Nullable结构中看不到声明的原因。

编译器魔法所做的正是实现细节,但我很确定它不会在object这里进行强制转换,因为您使用的是==(int, int). 根据规范,==(int, int)如果两个操作数都不为空,则这将适用(“底层运算符”)object.Equals

在sharplab.io 上,您可以看到该版本的编译器编译:

public bool F(int? a, int? b) {
    return a == b;
}

到:

public bool F(Nullable<int> a, Nullable<int> b)
{
    Nullable<int> num = a;
    Nullable<int> num2 = b;
    return (num.GetValueOrDefault() == num2.GetValueOrDefault()) & (num.HasValue == num2.HasValue);
}

对此的通用实现将是:

public static bool operator == (Nullable<T> a, Nullable<T> b) {
    return (a.GetValueOrDefault() == b.GetValueOrDefault()) && (a.HasValue == b.HasValue);
}

但请注意,上述内容不会在普通 C# 中编译,因为==不能保证在T. 然而,由于提升形式==(T?, T?)存在当且仅当 ==(T, T)存在,并且因为这是由编译器魔术实现的,所以我们很好。


以上是为什么Nullable&lt;T&gt;不会重载==运算符?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>