2011-09-29 112 views
10

Nullable<T>的定义是:为什么我不能写Nullable <Nullable <int>>?

[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: '诠释' 的类型必须是一个非空值类型,以便在通用类型或方法使用它作为类型参数“T”“System.Nullable” 编译失败:1个误差(S),0警告

+0

错误是什么? – asawyer

+2

对不起,我的回答是错误的。 'new Nullable ();'编译(产生一个值为null的int?'),尽管默认构造函数没有记录。 – BoltClock

+0

是的,答案出现在您尝试编译代码时应该得到的错误中。 – BoltClock

回答

5

从C#语言规范的4.1.10节:

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

9

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

如果约束为值类型约束(结构),该类型A必须满足下列之一:

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

请扩大规格报价。我并不完全明白这一点。我是C#的新手。 – Nawaz

+0

您应用于类的'struct'泛型类型约束是_specified_,意思是'除'Nullable '之外的所有值和枚举类型',特别是用于停止这种循环。 – thecoop

+0

@thecoop:这不是一个奇点。如果不是'Nullable'的类型参数的'struct'约束,可以有用''包含一个方法'Nullable 'TryGetValue(TKey)',而不必使用'out'参数。鉴于'Dictionary > myDict',在'var it = myDict.TryGetValue(“Fred”)后面;'如果'.HasValue'为false,那就意味着找不到键;如果'it.HasValue'为true,但是'it.Value.HasValue'为false,那么这意味着为关键字“Fred”存储了一个空值。真正的困难源于MS决定拥有...... – supercat

3

从C#4规范的§10.1.5:

值类型约束指定用于类型参数类型参数必须是一个非空值类型。所有不可为空的结构类型,枚举类型和具有值类型约束的类型参数均满足此约束条件。请注意,虽然分类为值类型,但是可以为空类型(§4.1。10)不满足值类型约束。具有值类型约束的类型参数不能具有构造函数约束。

1

正如其他人所说,规范禁止这一点。

挖越深,这是值得意识到你可以使自己的结构,使这种模式:

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

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

嵌套nullables的禁令不能使用提供给您和我的类型系统来表达。它仅在编译器(CS0453)中由特殊情况强制执行。


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

CS0451:“新()”约束不能用“结构”约束

所有的结构支持默认初始化反正使用。

+0

根据文档,不再有'new()'约束:https://referencesource.microsoft.com/#mscorlib/system/nullable.cs – series0ne

1

这不完全是一个答案,但只是思考的食物。

回合1

Nullable<Nullable<int>> a;

错误CS0453:类型'诠释?必须是一个非空值类型,以便在通用类型或方法“可为空”

智能感知提示来使用它作为参数“T” ... 该名称可以被简化


回合2

Nullable<int?>一个;

错误CS0453:类型'int?'必须是一个非空值类型,以便在通用类型或方法“可为空”

智能感知提示来使用它作为参数“T” ... 该名称可以被简化


回合3

int?? a;

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

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


结论

int?基本上只是一个Nullable<int>速记评价,但有作为int??没有这样的事情是我可以看到速记代表Nullable<Nullable<int>>的唯一途径。加int??借用空合并运算符,所以我很高兴这是不可能的,因为它看起来很可怕。 想象一下int????????????? a;毫无意义。

最后,由于Nullable的参考源没有产生任何强制执行的约束,我的猜测是这个约束被烘焙到CLR中,作为一种特殊情况,当可空值类型被引入到C#中时。

相关问题