Why can't I write Nullable>?

前端 未结 5 1132
陌清茗
陌清茗 2020-12-06 17:16

The definition of Nullable is:

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

The constraint

相关标签:
5条回答
  • 2020-12-06 17:54

    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).
    0 讨论(0)
  • 2020-12-06 17:55

    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 讨论(0)
  • 2020-12-06 18:12

    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.

    0 讨论(0)
  • 2020-12-06 18:12

    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.

    0 讨论(0)
  • 2020-12-06 18:14

    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.

    0 讨论(0)
提交回复
热议问题