Why does an implicit conversion operator from <T> to <U> accept <T?>?

  • A+

This is a weird behaviour that I cannot make sense of. In my example I am having a class Sample<T> and in an implicit conversion operator from T to Sample<T>.

private class Sample<T> {    public readonly T Value;     public Sample(T value)    {       Value = value;    }     public static implicit operator Sample<T>(T value) => new Sample<T>(value); } 

Now the problem occures when using a nullable value type for T such as int?.

{    int? a = 3;    Sample<int> sampleA = a; } 

Here is the key part:
In my opinion this should not compile because Sample<int> defines a conversion from int to Sample<int> but not from int? to Sample<int>. But it compiles and runs successfully! (By which I mean the conversion operator is invoked and 3 will be assigned to the readonly field.) But it gets even worse:

{    int? b = null;    Sample<int> sampleB = b; } 

Here the conversion operator isn't invoked and sampleB will be set to null.

A great answer would probably be split into two parts:

  1. Why does the code in the first snippet compile?
  2. Can I prevent the code from compiling in this scenario?

You can take a look at compiled version of this code:

int? a = 3; Sample<int> sampleA = a; 

that looks like this:

int? nullable = 3; int? nullable2 = nullable; Sample<int> sample = nullable2.HasValue ? ((Sample<int>)nullable2.GetValueOrDefault()) : null; 

Because Sample<int> is a class it's instance can be assigned a null value and with such an implicit opeartor the underlying type of a nullable object can also be assigned so assignments like this are valid:

int? a = 3; int? b = null; Sample<int> sampleA = a;  Sample<int> sampleB = b; 

If Sample<int> would be a struct that of course would give an error.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: