Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cast to multiple interfaces [duplicate]

Possible Duplicate:
Casting an object to two interfaces at the same time, to call a generic method

I'm fairly sure you can't do this so I'm wondering if there's a workaround, but I need/want to cast an object to represent multiple interfaces for use with generic constraints. For example:

public void Foo<T>(T t) where T : IInterfaceA, IInterfaceB
{
}

If I have an object I want to say something like var t = (IInterfaceA | IInterfaceB)someObj; so I can pass t into this method.

Is there a nifty way of doing this? I'm using C# 3.5 so no dynamic available, but if it's possible with dynamic please post it anyway.

like image 230
RichK Avatar asked May 31 '11 12:05

RichK


4 Answers

EDIT

Despite the answer below, I would say the better solution is the one that most other answers point to. (This assumes that you can redefine the multiple classes that implement both interfaces.)

Create an interface that inherits from both InterfaceA and InterfaceB, then, for all classes that implement interfaces A and B, replace those interfaces with the new one. Before:

class SomeClass : IInterfaceA, IInterfaceB { }
class AnotherClass : IInterfaceA, IInterfaceB { }
class AdditionalClass : IInterfaceA, IInterfaceB { }

After:

interface IInterfaceC : IInterfaceA, IInterfaceB { }
class SomeClass : IInterfaceC { }
class AnotherClass : IInterfaceC { }
class AdditionalClass : IInterfaceC { }

The implementation of Foo is then fairly trivial. And, again, since you don't know at compile time what type you have on hand, you may be able just to declare it as

public void Foo(IInterfaceC someObj) { }

END EDIT


You can do it using reflection, though some will say that this isn't particularly "nifty":

public class FooClass
{
    public void Foo<T> (T t) where T : IInterfaceA, IInterfaceB
    {
        //... do your thing here
    }
    private static void Example(object someObj)
    {
        var type = someObj.GetType();
        if(typeof(IInterfaceA).IsAssignableFrom(type) && typeof(IInterfaceB).IsAssignableFrom(type))
        {
            var genericMethod = typeof(FooClass).GetMethod("Foo");
            var constructedMethod = genericMethod.MakeGenericMethod(type);
            var instance = new FooClass();
            var result = constructedMethod.Invoke(instance, new [] { someObj });
            Assert.IsNull(result);
        }
    }
}

you could also do this, which could allow you to make Foo non-generic. It's also fairly ugly, so I would hide this ugliness by making it private:

private void PrivateFoo(IInterfaceA objA, IInterfaceB objB)
{
    if (!ReferenceEquals(objA, objB))
        throw new ArgumentException("objA and objB must refer to the same object");

    //... do your thing here
}
public void Foo(object someObj)
{
    PrivateFoo((IInterfaceA)someObj, (IInterfaceB)someObj);
}
like image 132
phoog Avatar answered Nov 19 '22 12:11

phoog


public void Foo<T>(T t) where T : IInterfaceA, IInterfaceB{}
{
  // T already implements IInterfaceA and IInterfaceB, just call the methods.
  t.MethodFromA();
  t.MethodFromB();
}

T t = (T)someObj;

This will cast the object to T, not the two interfaces... so it's up to you to make sure that'll work.


IInterfaceA tA = (IInterfaceA)someObj;
IInterfaceB tB = (IInterfaceB)someObj;

Two references to the one instance.

like image 42
Amy B Avatar answered Nov 19 '22 11:11

Amy B


No, there is no way.
The only thing that comes close is to create another interface the inherits those two interfaces. But then all your classes need to implement that third interface instead of the two others, so in most circumstances, this is not practical.

Just cast it to that interface you need at that moment.

UPDATE:
The only way I can see is to create a container class that implements those interfaces:

class Container : IInterfaceA, IInterfaceB
{
    private object _obj;

    public Container(object obj)
    {
        // Check that the object really implements those two interfaces.

        _obj = obj;
    }

    void IInterfaceA.Method1()
    {
        ((IInterfaceA)_obj).Method1();
    }

    // And so on for all methods of the interfaces.
} 
like image 2
Daniel Hilgarth Avatar answered Nov 19 '22 11:11

Daniel Hilgarth


One possible way to do this is have inheritance of interfaces. Move the common functionality, to the parent interface, which should be used in above scenarios.

like image 1
Ramesh PVK Avatar answered Nov 19 '22 11:11

Ramesh PVK