20

Let's say you define some arbitrary interface:

public interface IInterface {
    void SomeMethod();
}

And let's say there are some classes that happen to have a matching public interface, even though they do not "implement IInterface". IE:

public class SomeClass {
    public void SomeMethod() {
       // some code
    }
}

Is there nevertheless a way to get an IInterface reference to a SomeClass instance? IE:

SomeClass myInstance = new SomeClass();
IInterface myInterfaceReference = (IInterface)myInstance;
Dave Cousineau
  • 12,154
  • 8
  • 64
  • 80

6 Answers6

19

No there is no way to do this. If the type doesn't implement the interface then there is no way to cast to it. The best way to achieve behavior similar to the one you want is to create a wrapper type which provides an implementation of IInterface for SomeClass.

public static class Extensions {
  private sealed class SomeClassWrapper : IInterface {
    private readonly SomeClass _someClass;

    internal SomeClassWrapper(SomeClass someClass) {
      _someClass = someClass;
    }

    public void SomeMethod() {
      _someClass.SomeMethod();
    }
  }

  public static IInterface AsIInterface(this SomeClass someClass) {
    return new SomeClassWrapper(someClass);
  }
}

Then you can make the following call

SomeClass myInstance = new SomeClass();
IInterface myInterface = myInstance.AsIInterface();
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • It would also be possible using reflection to find the method in the wrapper for any class (or throw exception if not found) – Magnus Oct 10 '11 at 22:23
  • But how do you "uncast" it? or cast it back? The wrapper lost all connection. – jeromej Jul 03 '18 at 11:54
  • It is a true shame that this functionality doesn't exist, surely if the runtime knows an object supports the *exact same* public method(s)/property(s) it can justify an interface cast to an interface with those *exact same* public method(s)/property(s). – Zintom Jan 11 '22 at 16:16
  • @Zintom: Nope, because an interface is more than a set of method/property signatures. It is a binary layout of a vtable. That means (a) the order is important and (b) you can't have other intervening members. As a result, no "duck-typing" in .NET – Ben Voigt Feb 08 '23 at 16:42
7

CSScriptLibrary.dll has an extension method that 'aligns' an object instance to a given interface:

public static T AlignToInterface<T>(this object obj) where T : class;

Also check the rest of the library, it's a really helpful API when it comes to reflection an C# scripting.

Best regards.

jdearana
  • 1,089
  • 12
  • 17
6

If you have access to the source, you could always decorate the class, if not, you could make a wrapper:

public class InterfaceWrapper : IInterface
{
    private readonly SomeClass _someClass;

    public InterfaceWrapper(SomeClass someClass) { _someClass = someClass; }

    public void SomeMethod() { _someClass.SomeMethod(); }
}
Matthew Abbott
  • 60,571
  • 9
  • 104
  • 129
4

No. Just because two classes happen to have methods with the same name doesn't mean they abide by the same contract. That's why you define the contract by explicitly implementing the appropriate interface(s).

mellamokb
  • 56,094
  • 12
  • 110
  • 136
3

The method implemented by SomeClass may have the same signature as the one in the interface, but because it does not inherit / implement the interface there is no way to use a cast in this scenario - there is no "accidental" conformance - you have to explicitly state for each class that it implements a particular interface.

BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
1

This is now kind of doable with dynamic. It's not the same as getting a strongly typed reference, since that's impossible, but you can still treat otherwise unrelated types as the same if they happen to have members with the same signature.

// NOTE: no common interface
interface ISomething {
   void SomeMethod();
}

class SomethingElse {
   public void SomeMethod() {
   }
}

public void DoSomething(
   dynamic dyna
) =>
   dyna.SomeMethod();
...

ISomething something = GetSomething();
DoSomething(something);

var somethingElse = new SomethingElse();
DoSomething(somethingElse);

A concrete example of this is ListControl and the BeginUpdate/EndUpdate methods. Those methods are defined for the concrete types, but not on the base types. Using dynamic, whether you're working with a ComboBox, ListBox, or CheckedListBox, you can still call BeginUpdate without knowing which one you have.

Dave Cousineau
  • 12,154
  • 8
  • 64
  • 80