Search code examples
c#compiler-errorsnullabletypecast-operator

Error when trying to implement cast operator to nullable type in C#


I am currently creating a struct Nullsafe<T> that would wrap a reference type (hence T:class) and behave in a similar way to the Nullable<T> struct. The point is to emulate something close to what the Option<T> in F# does.

I intend to use the type in methods which I need to take special care of nulls. For example, assume I have a reference type class Foo, and the following code:

class Bar
{
    public void DoSomethingWithFoo(Nullsafe<Foo> foo);
}

Since I have created an implicit cast operator from T to Nullsafe<T>, then the below code would work fine:

Bar bar = new Bar();

Foo nullFoo = null;
bar.DoSomethingWithFoo(nullFoo);

Foo someFoo = new Foo();
bar.DoSomethingWithFoo(someFoo);

The Nullsafe<T> type is a struct (designed so on purpose, to eliminate passing any null values directly), therefore it is possible for someone to to write the below snippet:

Nullable<Nullsafe<Foo>> nullableNullsafeFoo = null;
// and later
bar.DoSomethingWithFoo(nullableNullsafeFoo);

The snippet, of cource, will not work.

So, I thought it would be a no-brainer to create a cast operator from within my Nullsafe<T> struct, which would handle nullable expressions like the above:

public static implicit operator Nullsafe<T>(Nullable<Nullsafe<T>> nv) => nv.GetValueOrDefault();

Unfortunately, this fails to compile. The compiler seems not to make a difference between the Nullsafe<T> and the Nullable<Nullsafe<T>> types, and throws at me the message:

Is the above a limitation of the compiler, or is it a purposedly intended behaviour? If so, are there any known workarounds?

error CS0555: User-defined operator cannot take an object of the enclosing type and convert to an object of the enclosing type

I am using:

  • Visual Studio Community 2017 v15.8.1
  • .NET Sdk v2.1.400 (as shown by dotnet --version

The project is a library multi-targeting different .NET framework versions - from net20 to netstandard2.0

Update

Is the above a limitation of the compiler, or is it a purposedly intended behaviour?

It seems this is indeed a result of the compiler stripping type information, as described by fellow user Isaac van Bakel.

If so, are there any known workarounds?

Doing as he adviced, I submitted an issue to the roslyn platform.


Solution

  • The observed behaviour is in fact intended and confirmed.

    A language design discussion thread was created, to address whether this behaviour should be changed in favour of use-cases like the above, or to otherwise provide a better compiler error message to be displayed.