Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
520 views
in Technique[技术] by (71.8m points)

c# - Why is Nullable<T> nullable? Why it cannot be reproduced?

When I write

Nullable<Nullable<DateTime>> test = null;

I get a compilation error:

The type 'System.Datetime?' must be a non-nullable value type in order to use it as a paramreter 'T' in the generic type or method 'System.Nullable<T>'

But Nullable<T> is a struct so it's supposed to be non-nullable.

So I tried to create this struct:

public struct Foo<T> where T : struct
{
    private T value;

    public Foo(T value)
    {
        this.value = value;
    }

    public static explicit operator Foo<T>(T? value)
    {
        return new Foo<T>(value.Value);
    }

    public static implicit operator T?(Foo<T> value)
    {
        return new Nullable<T>(value.value);
    }
}

Now when I write

        Nullable<Foo<DateTime>> test1 = null;
        Foo<Nullable<DateTime>> test2 = null;
        Foo<DateTime> test3 = null;

The first line is ok but for the second and third lines I get the two following compilation error:

The type 'System.DateTime?' must be a non-nullable value type in order to use it as a parameter 'T' in the generic type or method 'MyProject.Foo<T>' (second line only)

and

Cannot convert null to 'MyProject.Foo<System.DateTime?> because it is a non-nullable value type'

        Foo<Nullable<DateTime>> test = new Foo<DateTime?>();

doesn't work neither event if Nullable<DateTime> is a struct.

Conceptually, I can understand why Nullable<T> is nullable, it avoids having stuffs like DateTime?????????? however I can still have List<List<List<List<List<DateTime>>>>>...

So why this limitation and why can't I reproduce this behavior in Foo<T>? Is this limitation enforced by the compiler or is it intrinsic in Nullable<T> code?

I read this question but it just says that it is not possible none of the answers say fundamentally why it's not possible.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

But Nullable is a struct so it's supposed to be non-nullable.

Nullable<T> is indeed a struct, but the precise meaning of the generic struct constraint as stated in the docs is:

The type argument must be a value type. Any value type except Nullable can be specified. See Using Nullable Types (C# Programming Guide) for more information.

For the same reason, your line

Foo<Nullable<DateTime>> test2 = null;

results in the compiler error you are seeing, because your generic struct constraint restricts your generic T argument in a way so Nullable<DateTime> must not be specified as an actual argument.

A rationale for this may have been to make calls such as

Nullable<Nullable<DateTime>> test = null;

less ambiguous: Does that mean you want to set test.HasValue to false, or do you actually want to set test.HasValue to true and test.Value.HasValue to false? With the given restriction to non-nullable type arguments, this confusion does not occur.

Lastly, the null assignment works with Nullable<T> because - as implied by the selected answers and their comments to this SO question and this SO question - the Nullable<T> type is supported by some compiler magic.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...