Why can't I write Nullable<Nullable<int>>?
The definition of Nullable<T> is:
[SerializableAttribute]
public struct Nullable<T> where T : struct开发者_StackOverflow中文版, new()
The constraint where T : struct implies that T can only be a value type. So I very well understand that I cannot write:
Nullable<string> a; //error. makes sense to me
Because string is a reference type, not a value type. But I don't really understand why can't I write
Nullable<Nullable<int>> b; //error. but why?
Why is it not allowed? After all, Nullable<int> is a value-type, and therefore, it can be type argument to Nullablle<T>.
When I compiled it on ideone, it gives this error (ideone):
error CS0453: The type 'int?' must be a non-nullable value type in order to use it as type parameter 'T' in the generic type or method 'System.Nullable' Compilation failed: 1 error(s), 0 warnings
Because it's in the C# spec (section 4.4.4):
If the constraint is the value type constraint (struct), the type A must satisfy one of the following:
- A is a struct type or enum type, but not a nullable type. Note that System.ValueType and System.Enum are reference types that do not satisfy this constraint.
- A is a type parameter having the value type constraint (§10.1.5).
From section 4.1.10 of the C# language spec:
A non-nullable value type conversely is any value type other than
System.Nullable<T>and its shorthandT?(for anyT), plus any type parameter that is constrained to be a non-nullable value type (that is, any type parameter with astructconstraint). TheSystem.Nullable<T>type specifies the value type constraint forT(§10.1.5), which means that the underlying type of a nullable type can be any non-nullable value type. The underlying type of a nullable type cannot be a nullable type or a reference type. For example,int??andstring?are invalid types.
From §10.1.5 of the C# 4 spec:
The value type constraint specifies that a type argument used for the type parameter must be a non-nullable value type. All non-nullable struct types, enum types, and type parameters having the value type constraint satisfy this constraint. Note that although classified as a value type, a nullable type (§4.1.10) does not satisfy the value type constraint. A type parameter having the value type constraint cannot also have the constructor-constraint.
As others have said, the spec prohibits this.
Digging deeper, it's worth realising that you can make your own struct that allows this pattern:
struct Nestable<T> where T : struct { /* ... */ }
new Nestable<Nestable<int>>(); // This works just fine
The prohibition of nested nullables can not be expressed using the type system available to you and me. It is only enforced by a special case in the compiler (CS0453).
Aside: The new() constraint shown in the question doesn't actually exist on System.Nullable<T>. new() constraints are prohibited when using the struct constraint.
CS0451: The 'new()' constraint cannot be used with the 'struct' constraint
All structs support default initialisation anyway.
This isn't exactly an answer, but just food for thought.
Round 1
Nullable<Nullable<int>> a;
error CS0453: The type 'int?' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Nullable'
Intellisense hints... The name can be simplified
Round 2
Nullable<int?> a;
error CS0453: The type 'int?' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Nullable'
Intellisense hints... The name can be simplified
Round 3
int?? a;
error CS1519: Invalid token '??' in class, struct, or interface member declaration
error CS1525: Invalid expression term '??'
Conclusion
int? is essentially just a short-hand evaluation of Nullable<int>, but there's no such thing as int?? which is the only way I can see of representing Nullable<Nullable<int>> in short-hand. Plus int?? borrows the null-coalescing operator, so I'm glad it's not possible because it looks dreadful. Imagine int????????????? a; How pointless.
Finally, since the reference source for Nullable does not yield any constraints for enforcing this, my guess is that this constraint was baked into the CLR as a special case when nullable value types were introduced into C#.
加载中,请稍侯......
精彩评论