Home > OS >  Why doesn't return default(T?) give a null when T is constrained to enum?
Why doesn't return default(T?) give a null when T is constrained to enum?

Time:05-10

I have a parser that render text files into a datamodel. Some fields are optional, which are to be represented as null in the model.

However, a strange behavior is giving me a headache. When I handle nullable concretely, it behaves as expected.

Foo? a = null;

...works just fine.

Foo? b = default(Foo?);

...works also just fine. b is null.

However, whenever I wrap this inside a generic class, it seems that it has a difficulty treating the generic type parameter in the same way.

void Main()
{
    Foo? is_null = null;
    Foo? is_also_null = default (Foo?);

    Foo? does_not_work = FooClass.GetNull<Foo>();
    Foo? is_not_null = FooClass.GetDefault<Foo>();   // Should be null, AFAICT, but isn't,
    
}

public static class FooClass
{
    public static T? GetNull<T>() where T:System.Enum
    {
        return null;  //Compile error: CS0403 Cannot convert null to type parameter 'T' because it could be a non-nullable value type. Consider using 'default(T)' instead.
    }
    public static T? GetDefault<T>() where T : System.Enum
    {
        return default(T?); // Why does this not return null? Shouldn't this be the same as default(Foo?) ?
    }
}

public enum Foo
{
    one,two,three
}

What am I doing wrong? Or what am I missing here?

CodePudding user response:

enum constraints basically: don't work as you expect; the T : Enum doesn't mean it is treating it as a primitive - it is treating it as a boxed value (object) instead, that happens to be a sub-type of the Enum type (or Enum itself!). Emphasis: keep in mind that you could have used GetDefault<Enum> here.

The T? won't even compile without a compiler that supports Nullable Reference Types, and with NRT support and NRTs disabled: it will give you a CS8632 warning; this means that T? here refers to NRTs, and not Nullable<T>. You can fix this by adding the T : struct, Enum, but without that: default(T?) is just the same thing as default(T) (because the ? for NRTs doesn't change the type semantics - just whether we expect nulls or not), and default(T) is the zero enum.

  • Related