有没有办法声明一个在.Net中实现多个接口的变量?

时间:2010-05-03 03:18:09

标签: .net interface

this Java question相似。我想指定一个变量实现多个接口。例如

private {IFirstInterface, ISecondInterface} _foo;

public void SetFoo({IFirstInterface, ISecondInterface} value)
{
    _foo = value;
}

要求:

  • 我无法为大多数传入Foo的类型添加接口。所以我无法创建继承自IFirstInterface和ISecondInterface的第三个接口。
  • 我想避免在可能的情况下使包含类通用,因为Foo的类型与类没有太大关系,并且用户在编译时不太可能知道它。
  • 我需要在以后使用foo访问两个接口中的方法。
  • 我想以编译器安全的方式执行此操作,即在尝试使用它之前不尝试强制转换为接口。如果foo没有实现这两个接口,相当多的功能将无法正常工作。

这可能吗?

编辑:出于各种原因,我想要这几次。在这个例子中,因为我正在将一组属性从ObservableCollections更改为ReadOnlyObservableCollections。我有一个帮助器类,它创建从源ObservableCollection到另一个Collection的投影。由于ReadOnlyObservableCollection不从ObservableCollection继承而且我只需要IList和INotifyCollectionChanged中的操作,我希望将我的源集合存储为这两个接口的组合,而不是需要ObservableCollection。

4 个答案:

答案 0 :(得分:17)

如果您想限制方法SetFoo只采用实现这两个接口的参数,那么 运气

public void SetFoo<T>(T value) where T : IFirstInterface, ISecondInterface
{
    _foo = value;
}

从现在开始,只要您想要将_foo成员作为这两个接口之一访问,您只需通过强制转换访问它:(IFirstInterface)_foo或{{1分别。

你确实说过你想避免使用演员来保证编译时的安全;但我认为,如果你找到一种方法来确保(ISecondInterface)_foo使用上面的_foo进行初始化,你可以安心地投出你想要的一切。


我刚刚意识到以下内容描述了您没有想要做的问题中明确说明的内容。所以,我说,按照上面的说法进行操作。

另一个想法是,因为看起来这个SetFoo对象是一个类成员(我将这个假设基于变量名中的_foo),你可以在这里定义你的类方式:

_

这实际上是否有意义显然取决于您的具体情况。你肯定要考虑一下,因为有这种限制的类有时会导致你可能没想到的问题(例如class YourClassThatHasAFoo<T> where T : IFirstInterface, ISecondInterface { private T _foo; public void SetFoo(T value) { _foo = value; } } 现在必须采取参数键入SetFoo,而不只是实现两个接口的任何类。)

答案 1 :(得分:6)

不,没有办法以声明方式确保特定实例实现多个接口。

使用泛型可能有一种选择,但这实际上只适用于函数而不是属性。

public void Foo<T>(T arg)
    where T : IFirstInterface
    where T : ISecondInterface
{
    ...
}

使用类型推断,您应该能够像这样调用它:

ConcreteType bar = new ConcreteType(); // this implements both

Foo(bar);

答案 2 :(得分:2)

.NET中的变量有一个类型,类型可以实现多个接口。像这样:

public interface Interface1 { }
public interface Interface2 { }
public class SupportsMuliple : Interface1, Interface2 { }

但是从你的问题来看,似乎你想要一个变量实现多个接口,而没有一个实现这些接口的类型。这实际上是不可能的,但你可以动态生成一个实现接口的类型,并隐藏有一个真正的类型在做魔术的事实。模拟库moq使用Castle DynamicProxy执行此操作。

答案 3 :(得分:2)

可以定义接口,以便可能需要它们的任意组合并以类型安全的方式使用。关键是定义一个接口ISelf(Of Out T),其中一个成员Self是一个属性,通过该属性,对象将自身返回为T,然后为每个接口IFoo声明一个相应的IFoo形式( Out T),继承自IFoo和ISelf(Of T)。实现ISelf(Of Wowzo),IFoo(Of Wowzo),IBar(Of Wowzo)和IBoz(Of Wowzo)的Wowzo类将实现IFoo(Of IBar),IBar(Of IFoo),IFoo(IBoz) IBar)),IFoo(对于IBar(对于IBoo(对于IBoz(对于IBar)而言)))等,并且如果需要可以对任何这种类型进行类型转换。如果Thing是一个IFoo(IBar(Of IBoz)),可以直接使用它作为IFoo,或者使用Thing.Self作为IBar,或者使用Thing.Self.Self作为IBoz。

如何使用C#以这种方式组合三个接口的示例:

public interface ISelf<out T>
{
    T Self { get; }
}
interface IA { }
interface IA<T> : IA, ISelf<T> { }
interface IB { }
interface IB<T> : IB, ISelf<T> { }
interface IC { }
interface IC<T> : IC, ISelf<T> { }
class ConcreteThing
    : IA<ConcreteThing>
    , IB<ConcreteThing>
    , IC<ConcreteThing>
{
    public ConcreteThing Self => this;
}
public class ReferencingObject
{
    IA<IB<IC>> Thing { get; }

    void Method()
    {
        IA a = Thing;
        IB b = Thing.Self;
        IC c = Thing.Self.Self;
    }
}