0

I have the following struct:

struct Generic<T>
{
    public T Property { get; init; }
    public Generic(T property) { Property = property; }
    public static implicit operator T?(Generic<T> x)
        => x.GetHashCode() == 42 ? null : x.Property;
}

The compiler underlines the null in the implicit conversion and reports error CS0403:

Cannot convert null to type parameter T because it could be a non-nullable value type. Consider using default(T) instead.

But I do not define a conversion to T, I define it to T?! Why does the compiler not see this? And what can I do to get rid of the compiler error?

Strangely, these two nongeneric versions - one with T being a struct, one with T being a class - do not give any compiler errors:

struct NongenericStruct
{
    public int Property { get; init; }
    public NongenericStruct(int property) { Property = property; }
    public static implicit operator int?(NongenericStruct x)
        => x.GetHashCode() == 42 ? null : x.Property;
}

struct NongenericClass
{
    public string Property { get; init; }
    public NongenericClass(string property) { Property = property; }
    public static implicit operator string?(NongenericClass x)
        => x.GetHashCode() == 42 ? null : x.Property;
}
Kjara
  • 2,504
  • 15
  • 42
  • Is [this](https://dotnetfiddle.net/dE78IJ) an equivalent [mre]? – gunr2171 Jun 15 '22 at 11:46
  • `T?` is ambiguous between `struct?` and `class?` You need add a constraint. – shingo Jun 15 '22 at 11:47
  • @gunr2171 Looks equivalent to me, yes. But since I don't know what the compiler does internally, I am not sure. At least both give the same compiler error. – Kjara Jun 15 '22 at 11:49
  • @gunr2171 Yes, your link answers my question: "There's no way that you can specify a generic parameter such that you can treat it as a class and a nullable value type." Which does not answer WHY that is so, unfortunately... Anyway, my follow-up question "What if I use default(T?) instead of null?" (which also does not work) is answered by Marc Gravell's first comment below [that](https://stackoverflow.com/q/72434798/5333340) question. – Kjara Jun 15 '22 at 12:19

1 Answers1

0

A nullable reference type is not the same as a nullable value type.

As the generic type T has no constraint, the compiler cannot explicitly convert null into either a Nullable<T> (struct) or a T? (class).

In order to fix this you have to explicitly tell the compiler if it's a reference or a value type with a generic type constraint.

// reference type
where T : class

// value type
where T : struct
Hervé
  • 760
  • 4
  • 9
  • And what if I want my `Generic` type to work for both `struct` and `class` `T`? Is there no other way than defining two `Generic` types? If there is so much difference in that piece of code depending on `T`, why doesn't the compiler just generate two versions? – Kjara Jun 15 '22 at 11:58
  • @Kjara if `Generic` was a class you could use inheritance but since it's a struct i dont thing it is an other way than 2 structs – Hervé Jun 15 '22 at 12:00