为什么我不能写Nullable <nullable <int>&gt;?</nullable <int>

时间:2011-09-29 12:20:44

标签: c# nullable value-type

Nullable<T>的定义是:

[SerializableAttribute]
public struct Nullable<T> where T : struct, new()

约束where T : struct意味着T只能是值类型。所以我很清楚我不能写:

Nullable<string> a; //error. makes sense to me

因为string是引用类型,而不是值类型。但我真的不明白为什么我不能写

Nullable<Nullable<int>> b; //error. but why?

为什么不允许?毕竟,Nullable<int>是一个值类型,因此它可以是Nullablle<T>的类型参数。

当我在ideone上编译它时,它会出现此错误(ideone):

  

错误CS0453:类型'int?'必须是非可空值类型才能在泛型类型或方法'System.Nullable'中将其用作类型参数'T'   编译失败:1个错误,0个警告

5 个答案:

答案 0 :(得分:10)

因为它在C#规范中(第4.4.4节):

  

如果约束是值类型约束(struct),则类型A必须满足以下条件之一:

     
      
  • A是结构类型或枚举类型,但不是可空类型。请注意,System.ValueType和System.Enum是不满足此约束的引用类型。
  •   
  • A是具有值类型约束(第10.1.5节)的类型参数。
  •   

答案 1 :(得分:6)

从C#语言规范4.1.10开始:

  

非可空值类型 相反,是除System.Nullable<T>以外的任何值类型及其简写T?(对于任何T }),加上任何被约束为非可空值类型的类型参数(即具有struct约束的任何类型参数)。 System.Nullable<T>类型指定T(第10.1.5节)的值类型约束,这意味着可空类型的基础类型可以是任何不可为空的值类型。可空类型的基础类型不能是可空类型或引用类型。例如,int??string?是无效类型。

答案 2 :(得分:4)

来自C#4规范的§10.1.5:

  

值类型约束指定用于type参数的类型参数必须是非可空值类型。具有值类型约束的所有非可空结构类型,枚举类型和类型参数都满足此约束。请注意,虽然归类为值类型,但可空类型(第4.1.10节)不满足值类型约束。具有值类型约束的类型参数也不能具有构造函数约束。

答案 3 :(得分:2)

正如其他人所说,该规范禁止这样做。

深入挖掘,值得认识到你可以制作自己允许这种模式的结构:

struct Nestable<T> where T : struct { /* ... */ }

new Nestable<Nestable<int>>(); // This works just fine

使用您和我可用的类型系统无法表示禁止嵌套的nullables。它仅由编译器中的特殊情况强制执行(CS0453)。

旁白:问题中显示的new()约束实际上并不存在于System.Nullable<T>上。使用new()约束时禁止struct个约束。

  

CS0451:'new()'约束不能与'struct'约束

一起使用

无论如何,所有结构都支持默认初始化。

答案 4 :(得分:2)

这不是一个答案,而只是值得深思。

第1轮

Nullable<Nullable<int>> a;

  

错误CS0453:类型'int?'必须是不可为空的值类型才能在泛型类型或方法'Nullable'中将其用作参数'T'

Intellisense暗示...... 名称可以简化

第2轮

Nullable<int?> a;

  

错误CS0453:类型'int?'必须是不可为空的值类型才能在泛型类型或方法'Nullable'中将其用作参数'T'

Intellisense暗示...... 名称可以简化

第3轮

int?? a;

  

错误CS1519:无效的令牌'??'在类,结构或接口成员声明中

     

错误CS1525:无效的表达式术语'??'

<强>结论

int?基本上只是对Nullable<int>的简短评估,但没有int??这样的东西,这是我能看到代表Nullable<Nullable<int>>的唯一方式速记。加int??借用null-coalescing运算符,所以我很高兴它不可能因为它看起来很可怕。 想象一下int????????????? a; 多么无意义。

最后,由于Nullable的引用源没有产生任何强制执行的约束,我的猜测是当Cul中引入了可空值类型时,这个约束被作为特殊情况引入CLR。