如何为null<;T>;不同于类似的自定义C#结构

本文关键字:结构 自定义 不同于 null lt gt | 更新日期: 2023-09-27 17:49:18

在Nullable微优化的第一部分中,Eric提到Nullable<T>具有类似用户定义类型无法实现的奇怪装箱行为。

C#语言赋予预定义的Nullable<T>类型哪些特殊功能?尤其是那些无法在MyNullable类型上工作的。

当然,Nullable<T>有特殊的句法糖T?,但我的问题更多的是关于语义。

如何为null<;T>;不同于类似的自定义C#结构

我得到的是:不存在可以为null装箱的东西。当您装箱一个int时,您会得到一个对装箱的int的引用。当您装箱一个int?时,您会得到一个空引用或对装箱的int的引用。你永远不会得到盒装的int?

您可以很容易地创建自己的Optional<T>结构,但无法实现具有装箱行为的结构。Nullable<T>的特殊行为被烘焙到运行时中。

这一事实导致了许多奇怪的事情。例如:

  • C#4:动态且可为空<gt;

  • C#反射:如何获取Nullable<int>?

  • 无法在泛型方法中将类型更改为可为null

仅供参考,Nullable<T>型还有其他"神奇"的方式。例如,虽然它是一个结构类型,但它不满足结构约束。您无法创建具有该属性的自己的结构。

我在C#规范中发现了这两个:

  • is运算符在T?上的作用与在T上的作用相同,而as运算符可以转换为可为null的类型
  • 对不可为null的值类型进行操作的预定义运算符和用户定义运算符将提升为这些类型的可为null形式

现在,以下是我认为而非仅限于Nullable<T>:的功能

  • switch中的值可以是可为null的类型。我认为这并不重要,因为switch还接受可以在MyNullable类型上定义的用户定义的隐式转换
  • 支持可为null的IDisposable类型,在生成对Dispose((的调用之前插入null检查。我认为这不重要,因为我可以将MyNullable定义为一个类,然后它也会是一样的

以下是我不确定的内容:

  • 规范中提到了装箱/取消装箱和隐式/显式转换,但我不明白MyNullable是否可以实现相同的结果
C#提升可为null类型上的运算符。例如:
int? SumNullableInts(int? a, int? b)
{
    return a + b;
}

为了支持这一点,您必须在MyNullable<T>中做大量的反射工作,然后在不应该编译的地方编译以下内容:

MyNullable<List<string>.Enumerator> SumNullableEnumerators(MyNullable<List<string>.Enumerator> a, MyNullable<List<string>.Enumerator> b)
{
    return a + b;
}