Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this implicit type conversion in C# fail?

Background:

Let's assume I've got the following class:

class Wrapped<T> : IDisposable
{
    public Wrapped(T obj)  { /* ... */ }

    public static implicit operator Wrapped<T>(T obj)
    {
        return new Wrapped<T>(obj);
    }

    public void Dispose()  { /* ... */ }
}

As you can see, it provides an implicit type conversion operator for TWrapped<T>. Ultimately, I would like to be able to use this class as follows:

interface IX  { /* ... */ }

class X : IX  { /* ... */ }

...

IX plainIX = new X();

using (Wrapped<IX> wrappedIX = plainIX)
{
    /* ... */
} 

Problem:

However, the type conversion in the above using clause fails. While I can assign a new X() directly to wrappedIX, I am not allowed to assign anything of type IX to it. The compiler will complain with the following error:

Compiler error CS0266: Cannot implicitly convert type 'IX' to 'Wrapped<IX>'. An explicit onversion exists (are you missing a cast?)

I don't understand this. What's the problem here?

like image 716
stakx - no longer contributing Avatar asked Mar 26 '10 19:03

stakx - no longer contributing


1 Answers

I believe it's because IX is an interface. The compiler thinks that maybe a value of type IX could already be derived from Wrapped<IX> (even if Wrapped<T> is sealed) so it doesn't use the conversion.

The details are quite complicated, in sections 6.4.3 and 6.4.4 of the C# 3.0 spec. Basically because IX is an interface, it's not "encompassed by" any types, which means a later step in 6.4.4 fails.

I suggest you create a non-generic type Wrapped with this method:

public static Wrapped<T> Of<T>(T item)
{
    return new Wrapped<T>(item);
}

Then you can just write:

using (Wrapped<IX> wrappedIX = Wrapped.Of(plainIX))

Basically conversions can be a bit tricky for various reasons - simple methods are generally easier to understand, IMO.

like image 183
Jon Skeet Avatar answered Sep 24 '22 01:09

Jon Skeet