0

I have a class that doesn't implement an interface, but it needs to. I can't change the class itself, so I wanted to create an implicit operator from ClassA to IInterface. This can't be done by design (I get the message: "User-defined conversion to interface"). So I want to create an adapter for it like so:

    public interface IInterface
    {
        void Method();
    }

    public class ClassA
    {
        public void Implementation()
        {
        }
    }

    public class ClassAToIInterfaceAdapter : IInterface
    {
        public ClassAToIInterfaceAdapter(ClassA classA)
        {
            ClassA = classA;
        }

        public void Method()
        {
            ClassA.Implementation();
        }

        private ClassA ClassA { get; set; }

        public static implicit operator ClassAToIInterfaceAdapter(ClassA classA)
        {
            return new ClassAToIInterfaceAdapter(classA);
        }
    }

    public void Test2()
    {
        var classA = new ClassA();
        IInterface i = classA;
    }

Here I get the compiler error:

error CS0266: Cannot implicitly convert type 'ClassA' to 'IInterface'. An explicit conversion exists (are you missing a cast?)

Adding an explicit cast will fix the compiler error, but not the runtime error:

Unable to cast object of type 'ClassA' to type 'IInterface'

Two questions about this:

  1. Why does this error occur? There is a cast possible from ClassA to IInterface.
  2. Can this be done at all without explicitly using the adapter in the code?
ssilas777
  • 9,672
  • 4
  • 45
  • 68
Jeroen
  • 979
  • 1
  • 7
  • 16
  • @AdamHouldsworth This is for a DSL, so adding the explicit casts makes it a lot less usable and readable. In the project I want to use this in, it is preferred to have it implicit. – Jeroen Jan 03 '14 at 11:40
  • Usable, debatable. Readable, perhaps. Understandable? Definitely not. But your requirements are what they are so I'm not arguing with that, my solution may be applicable to other people who view this question. – Adam Houldsworth Jan 03 '14 at 11:41
  • Everything is debatable, except for this. It is what it is. After the DSL is complete, it will be understandable (but you need to see it in action). – Jeroen Jan 03 '14 at 11:44
  • Maybe Roslyn will enable you to add custom compilation support for this, but otherwise there is no way to get that code to work without extra code such as an middle-man cast or explicit cast. Unfortunately, I have no experience with Roslyn so cannot flesh out any details. – Adam Houldsworth Jan 03 '14 at 11:45
  • Once you do define your own wrapper class, can't you define implicit conversions then? – Mark Hurd Jan 03 '14 at 11:46
  • @AdamHouldsworth Didn't know about Roslyn, but it looks interesting. Can't use it in our project, but it has been added to my todo-list. – Jeroen Jan 03 '14 at 11:51

1 Answers1

1

The reason the error occurs is that, yes there is a cast possible, but you are not indicating anywhere (in your method Test2) that the conversion should be done using the ClassAToInterfaceAdapter class. You could have a dozen implicit operators defined in as many classes, but that is no reason to use them.

You have to indicate the type, and if the type has an implicit operator, than it will be used. This works because the type ClassAToInterfaceAdapter contains the implicit operator:

public void Test2() {
    var classA = new ClassA();
    ClassAToInterfaceAdapter i = classA;
}

Edit:

From another SO answer

The reason you can't do this is because it is specifically forbidden in the C# language specification:

A class or struct is permitted to declare a conversion from a source type S to a target type T provided all of the following are true:

  • ...
  • Neither S nor T is object or an interface-type.

and

User-defined conversions are not allowed to convert from or to interface-types. In particular, this restriction ensures that no user-defined transformations occur when converting to an interface-type, and that a conversion to an interface-type succeeds only if the object being converted actually implements the specified interface-type.

Source

Community
  • 1
  • 1
Maarten
  • 22,527
  • 3
  • 47
  • 68
  • Thanks. That was it. If I make IInterface into an abstract class, I get the result I want. I'll have to see if that is going to be possible in the system. – Jeroen Jan 03 '14 at 11:48