10

为什么禁止以下内容?

Nullable<Nullable<int>>

然而

struct MyNullable <T>
{


}

MyNullable<Nullable<int>> 

不是

4

5 回答 5

19

这是因为结构约束实际上意味着“不可为空”,因为尽管 Nullable 是一个结构,但它是可以为空的(可以接受 null 值),Nullable<int>它不是外部 Nullable 的有效类型参数。

这在约束文档中明确说明

其中 T: struct
类型参数必须是值类型。可以指定除 Nullable 之外的任何值类型。
有关更多信息,请参阅使用 Nullable 类型(C# 编程指南)。

如果您想要这样做的理由,您将需要我找不到的实际语言设计者对此的评论。但是我会假设:

  1. 以当前形式实现 Nullable 所需的编译器和平台更改非常广泛(并且是 2.0 版本中相对最后一分钟的补充)。
  2. 他们有几个可能令人困惑的边缘情况。

允许相当于 int?? 只会混淆这一点,因为该语言没有提供区分 Nullable<Nullable<null>>和 Nullable的方法,<null>也没有任何明显的解决方案。

Nullable<Nullable<int>> x = null;
Nullable<int> y = null;
Console.WriteLine(x == null); // true
Console.WriteLine(y == null); // true
Console.WriteLine(x == y); // false or a compile time error!

在涉及 Nullable 类型的许多操作中,使该返回为真将是非常复杂且显着的开销。

CLR 中的某些类型是“特殊的”,例如字符串和原语,因为编译器和运行时对彼此使用的实现有很多了解。Nullable 在这种情况下也很特殊。由于它已经在其他领域特殊外壳特殊外壳,所以这where T : struct方面没什么大不了的。这样做的好处是处理泛型类中的结构,因为除了 Nullable 之外,它们都不能与 null 进行比较。这意味着 jit 可以安全地认为t == null总是错误的。

在语言被设计为允许两个非常不同的概念交互的地方,你往往会变得奇怪、混乱或危险的边缘情况。例如,考虑 Nullable 和相等运算符

int? x = null;
int? y = null;
Console.WriteLine(x == y); // true
Console.WriteLine(x >= y); // false!     

通过在使用 struct 泛型约束时防止 Nullables,可以避免许多讨厌(且不清楚)的边缘情况。

至于从第 25.7 节(强调我的)中强制执行此操作的规范的确切部分:

值类型约束指定用于类型参数的类型参数必须是值类型(第 25.7.1 节)。任何具有值类型约束的不可为空的结构类型、枚举类型或类型参数都满足此约束。具有值类型约束的类型参数也不应具有构造函数约束。System.Nullable 类型为 T 指定不可为空的值类型约束。 因此,T?? 形式的递归构造类型 和 Nullable <Nullable <T>>是被禁止的。

于 2009-03-01T17:19:05.630 回答
14

我相信您只能在Nullables 中使用不可为空的值类型。由于Nullable本身可以为空,因此禁止以这种方式嵌套。

来自http://msdn.microsoft.com/en-us/library/kwxxazwb.aspx

public Nullable(
    T value
)

类型:TA值类型。

于 2009-03-01T17:10:52.517 回答
3

Nullable 是特殊的,因为 CLR 中内置了对 Nullable 类型的装箱和拆箱的显式支持:

如果您box对 a 使用 MSIL 指令Nullable<T>,您实际上会得到 anull作为结果。没有其他值类型会在装箱时产生空值。

对拆箱有类似且对称的支持。

于 2009-03-01T17:45:58.733 回答
2

Nullable 的泛型类型参数本身必须是不可为空的类型(即值类型)。这是我得到的 C# 编译器警告,它似乎是有道理的。告诉我,你为什么要做这样的事情?我个人认为这样的声明没有用,甚至没有什么意义。

于 2009-03-01T17:12:11.763 回答
0

Nullable 允许您采用值类型并将其设为引用类型,即该值存在或不存在(为空)。由于引用类型已经可以为空,因此是不允许的。

引用自MSDN

Nullable(T) 结构仅支持将值类型用作可空类型,因为引用类型在设计上可以为空。

于 2009-03-01T17:13:25.350 回答