为什么禁止以下内容?
Nullable<Nullable<int>>
然而
struct MyNullable <T>
{
}
MyNullable<Nullable<int>>
不是
这是因为结构约束实际上意味着“不可为空”,因为尽管 Nullable 是一个结构,但它是可以为空的(可以接受 null 值),Nullable<int>
它不是外部 Nullable 的有效类型参数。
这在约束文档中明确说明
其中 T: struct
类型参数必须是值类型。可以指定除 Nullable 之外的任何值类型。
有关更多信息,请参阅使用 Nullable 类型(C# 编程指南)。
如果您想要这样做的理由,您将需要我找不到的实际语言设计者对此的评论。但是我会假设:
允许相当于 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>>
是被禁止的。
我相信您只能在Nullable
s 中使用不可为空的值类型。由于Nullable
本身可以为空,因此禁止以这种方式嵌套。
来自http://msdn.microsoft.com/en-us/library/kwxxazwb.aspx
public Nullable( T value )
类型:TA值类型。
Nullable 是特殊的,因为 CLR 中内置了对 Nullable 类型的装箱和拆箱的显式支持:
如果您box
对 a 使用 MSIL 指令Nullable<T>
,您实际上会得到 anull
作为结果。没有其他值类型会在装箱时产生空值。
对拆箱有类似且对称的支持。
Nullable 的泛型类型参数本身必须是不可为空的类型(即值类型)。这是我得到的 C# 编译器警告,它似乎是有道理的。告诉我,你为什么要做这样的事情?我个人认为这样的声明没有用,甚至没有什么意义。
Nullable 允许您采用值类型并将其设为引用类型,即该值存在或不存在(为空)。由于引用类型已经可以为空,因此是不允许的。
引用自MSDN:
Nullable(T) 结构仅支持将值类型用作可空类型,因为引用类型在设计上可以为空。