转换为多个接口

时间:2011-05-31 12:19:22

标签: c# generics casting

  

可能重复:
  Casting an object to two interfaces at the same time, to call a generic method

我很确定你不能这样做所以我想知道是否有解决方法,但我需要/想要转换一个对象来表示多个接口以用于泛型约束。例如:

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

如果我有一个对象我想说var t = (IInterfaceA | IInterfaceB)someObj;之类的东西,那么我可以将t传递给这个方法。

有一种漂亮的方式吗?我正在使用C#3.5,因此没有动态可用,但如果可以动态,请发布它。

5 个答案:

答案 0 :(得分:3)

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;

这会将对象强制转换为T,而不是两个接口......因此,您需要确保它能正常工作。


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

对一个实例的两次引用。

答案 1 :(得分:3)

修改

尽管下面给出了答案,但我认为更好的解决方案是大多数其他答案指向的解决方案。 (这假设您可以重新定义实现两个接口的多个类。)

创建一个继承InterfaceA和InterfaceB的接口,然后,对于实现接口A和B的所有类,将这些接口替换为新接口。之前:

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

后:

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

Foo的实现非常简单。而且,再次,因为您在编译时不知道您手头有什么类型,您可以将其声明为

public void Foo(IInterfaceC someObj) { }

结束编辑


你可以使用反射来做,虽然有人会说这不是特别“漂亮”:

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);
        }
    }
}

你也可以这样做,这可以让你使Foo非泛型。它也相当丑陋,所以我会把它隐藏起来隐藏这个丑陋:

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);
}

答案 2 :(得分:2)

不,没有办法 唯一接近的是创建另一个继承这两个接口的接口。但是,所有类都需要实现第三个接口而不是其他两个接口,因此在大多数情况下,这是不切实际的。

只需将其投射到您当时需要的界面即可。

<强>更新
我能看到的唯一方法是创建一个实现这些接口的容器类:

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.
} 

答案 3 :(得分:1)

执行此操作的一种可能方法是继承接口。将公共功能移动到父接口,这应该在上面的场景中使用。

答案 4 :(得分:0)

您可以重新构建您的继承以实现目标。

public class ArrayList : IList, ICollection, IEnumerable, ICloneable
public interface IList : ICollection, IEnumerable

请注意来自IList的ArrayList inerits,它继承自Arraylist中已包含的两个接口。