2

Before I state my issue let me give some background information on what I'm trying to do, because perhaps there's a better way to achieve it.

I got a class C which inherits two interfaces A and B.

public interface A
{
    void DoStuff();
}

public interface B
{
    void DoStuff();
}

C implements two different bodies for DoStuff.

void A.DoStuff()
{
    Console.WriteLine("A");
}

void B.DoStuff()
{
    Console.WriteLine("B");
}

I know of course DoStuff can be called like below.

var c = new C();
var a = (A)c;
a.DoStuff();
var b = (B)c;
b.DoStuff();

What I want to do though is to avoid converting C to either A or B and then calling DoStuff on A or B.

So what I though was that I could implement a generic method to do this for me and so I first tried like this.

public void DoStuff<T>()
{
    var i = (T)this;
    i.DoStuff();
}

Of course that won't work considering you can convert this to T and it causes a compiler error, so my next step was to try to create a static method that passed the instance of this and then did the conversion in there.

private static To ConvertToDoStuffInterface<From, To>(From from)
{
    return (To)from;
}

I did not expect that to work, but it was worth a try. As I expected it would cause a compiler error, because From cannot explicitly convert to To.

My last resort was using the dynamic keyword and of course it smoothy gets through ConvertToDoStuffInterface, but once I try to call DoStuff it throws a RuntimeBinderException which I kinda suspected it might would. I know why the exception is thrown and it's of course because it can't properly bind the result from ConvertToDoStuffInterface to any type and some kind of casting is required I assume.

Here is the code for the dynamic usage.

private static dynamic ConvertToDoStuffInterface<T>(dynamic from)
{
    return (T)from;
}

public void DoStuff<T>()
{
    var i = ConvertToDoStuffInterface<T>(this);
    i.DoStuff();
}

My question though is if there is no better way to achieve this using either generics or dynamic, how would I go about doing the conversion from dynamic to T? Is there a way that I could check if the passed type to DoStuff<T> has a method DoStuff and then allow what I attempted at first?

To clarify what I want to be able to do is something like this

var c = new C();
c.DoStuff<A>(); // Calls A.DoStuff()
c.DoStuff<B>(); // Calls B.DoStuff()

Here is my C implementation.

public class C : A, B
{        
    public void DoStuff<T>()
    {
        // ... DoStuff<T> implementation here ...
    }

    void A.DoStuff()
    {
        Console.WriteLine("A");
    }

    void B.DoStuff()
    {
        Console.WriteLine("B");
    }
}
Bauss
  • 2,767
  • 24
  • 28

3 Answers3

2

You could use these two InvokeAsextension methods

public static void InvokeAs<T>(this object obj, Action<T> action)
{
    action((T) obj);
}

public static TResult InvokeAs<T, TResult>(this object obj, Func<T, TResult> func)
{
    return func((T) obj);
}

And then use like this:

var c = new C();

c.InvokeAs<A>(x => x.DoStuff());
c.InvokeAs<B>(x => x.DoStuff());

But as pointed out in the comments, ((B) c).DoStuff() is not all that bad.

dcastro
  • 66,540
  • 21
  • 145
  • 155
  • This is probably the closest to what I want, but I think if this is the only way I'll go with `((B)c).DoStuff()` – Bauss Aug 27 '15 at 13:11
1

To have the behavior exactly as you want, you can use reflection:

class C : A, B
{
    void B.DoStuff()
    {
        Console.WriteLine("B");
    }

    void A.DoStuff()
    {
        Console.WriteLine("A");
    }

    public void DoStuff<T>() 
    {
        var mi = typeof(T).GetMethod("DoStuff");
        mi.Invoke(this, new object[] { });
    }
}

then the call:

        var c = new C();
        c.DoStuff<A>();
        c.DoStuff<B>();
        Console.ReadLine();

works as expected. Obviously you would have to make proper validation in the DoStuff method, if the "DoStuff" method exists and so on.

However - I don't know the use case - but it seems for me not so obvious why this is for you bether than casting.

alek kowalczyk
  • 4,896
  • 1
  • 26
  • 55
  • Yup, as I said, I don't know your use case, it works, and it can be optimized, e.g. by assigning the method to a cached delegate. – alek kowalczyk Aug 27 '15 at 13:14
1

I agree that casting is probably the cleanest (assuming you can't fix the name conflict in the interfaces), but another way would be to create two instance methods on C to wrap the interface calls:

public class C : A, B
{        
    public void DoStuff<T>()
    {
        // ... DoStuff<T> implementation here ...
    }

    void A.DoStuff()
    {
        Console.WriteLine("A");
    }

    void B.DoStuff()
    {
        Console.WriteLine("B");
    }

    public void DoStuffAsA() { ((A)this).DoStuff(); }
    public void DoStuffAsB() { ((B)this).DoStuff(); }
}

At least it gives you compile-time safety that dynamic, reflection and generics don't.

D Stanley
  • 149,601
  • 11
  • 178
  • 240