开发者

Why can't I write Nullable<Nullable<int>>?

开发者 https://www.devze.com 2023-04-09 02:14 出处:网络
The definition of Nullable<T> is: [SerializableAttribute] public struct Nullable<T> where T : struct开发者_StackOverflow中文版, new()

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 shorthand T? (for any T), plus any type parameter that is constrained to be a non-nullable value type (that is, any type parameter with a struct constraint). The System.Nullable<T> type specifies the value type constraint for T (§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?? and string? 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#.

0

精彩评论

暂无评论...
验证码 换一张
取 消