C# 我是否可以将成员定义/约束为实现两个接口,而不使用泛型?

C# 我是否可以将成员定义/约束为实现两个接口,而不使用泛型?,c#,.net,oop,design-patterns,interface,C#,.net,Oop,Design Patterns,Interface,下面的代码显示了我想做什么;也就是说,我想约束一个对象,这样它就可以作为使用IInterfaceOne或IInterfaceTwo的各种方法的参数,而这两种方法都不能从另一个继承 public interface IInterfaceOne { } public interface IInterfaceTwo { } public class Implementation : IInterfaceOne, IInterfaceTwo { } public interface IInterfa

下面的代码显示了我想做什么;也就是说,我想约束一个对象,这样它就可以作为使用IInterfaceOne或IInterfaceTwo的各种方法的参数,而这两种方法都不能从另一个继承

public interface IInterfaceOne { }
public interface IInterfaceTwo { }

public class Implementation : IInterfaceOne, IInterfaceTwo
{
}

public interface IInterfaceOneAndTwo : IInterfaceOne, IInterfaceTwo { }

public class UsingImplementation
{
    IInterfaceOneAndTwo anObject = (IInterfaceOneAndTwo)(new Implementation()); //fails because Implementation doesnt acctually implement IInterfaceOneAndTwo
}
然而,这个例子失败了,因为IInterfaceOneAndTwo本身就是一个接口,而实现并没有实现它

我知道如果我使用泛型,我可以约束它们,但我想知道,如果没有泛型,是否有办法做到这一点


有没有一种方法可以说
一个对象
应该实现
IInterfaceOne
IInterfaceTwo
,而不使用
IInterfaceOne和two

不是您目前的方式。只有泛型约束才具有这种能力

您可以重写它以使用泛型:

public class UsingImplementation<T>
   where T : IInterface1, IInterface2, new()
{
    T anObject = new T();

    void SomeMethod() {
       anObject.MethodFromInterface1();
    }
}
使用实现的公共类
其中T:IInterface1,IInterface2,new()
{
T anObject=新的T();
void方法(){
anObject.MethodFromInterface1();
}
}

如果需要,那么IIinterfaceOne和IIinterfacetwo之间必须有逻辑连接,实现类应该实现组合接口:

class Implementation : IInterfaceOneAndTwo { ... }

如果这是不可能的,因为它不是(全部)您的代码,那么您可能需要重新考虑使用实现。它根本不适合可用的曲面

您还可以使用泛型方法,而不仅仅是泛型类

public void DoSomething<T>(T value)
    where T : IInterface1, IInterface2
{
    value.DoInterface1Things();
    value.DoInterface2Things();
}
public void DoSomething(T值)
其中T:i接口1,i接口2
{
value.DoInterface1Things();
value.doInterface2tings();
}

public void DoSomething()
其中T:IInterface1,IInterface2,new()
{
T anObject=新的T();
}
“传入的”泛型类参数和泛型方法参数可以组合类型,但变量或字段无法表示“复合”类型。此外,为了将对象传递给包含多个约束的泛型类型的参数,必须将对象转换为实际上实现所有这些约束的类型。这可能很困难

例如,假设类
Foo
Bar
都实现了
Intf1
Intf2
。我们希望编写一个函数
AddToList(作为T的东西),其中T:Intf1,Intf2
。这样的函数完全可以接受
Foo
Bar
类型的对象。但是,假设希望使用此函数将所有对象添加到同一列表中(可能是
Foo
Bar
,以及碰巧实现
Intf1
Intf2
的任何其他类型的混合体)然后将这些对象传递给一个函数,该函数的参数同样被约束以实现
Intf1
Intf2
。人们可以将任何碰巧是
Foo
的对象转换为
Foo
,也可以将任何碰巧是
Bar
的对象转换为
Bar
,但如果编写的其他类型也处理
Intf1
Intf2
,则很难处理它们

不使用反射或其他类似的技巧就可以解决问题,这有点尴尬。使用方法
ActUponActUpon(thingType thing)定义接口
IActUpon
,其中thingType:Base1,Base2
。这种方法的实现将能够将参数
thing
传递给需要将通用方法参数约束为
Base1
Base2
的其他方法。这种方法的最大困难在于必须为每个可能的约束数编写单独的代码,在许多地方,如果使用lambda表达式,则必须编写
IActUpon…

的实现,在没有泛型的C语言中,您无法实现这一点,但是有一种替代方法可以解决没有泛型的问题,这里没有提到,并且可能适合您。这种风格通常与国际奥委会的原则一起使用。可以将同一对象注入两次。让我把你的样品改一下

public interface IInterfaceOne { void Hello(); } 
public interface IInterfaceTwo { void World(); } 

public class Implementation : IInterfaceOne, IInterfaceTwo
{
   public void Hello() { };
   public void World() { };
} 

public class UsingImplementation 
{
   private readonly IInterfaceOne one;
   private readonly IInterfaceTwo two;

   public UsingImplentation(IInterfaceOne one, IInterfaceTwo two)
   {
      this.one = one;
      this.two = two;
   }

   // do the stuff you want to do with an IInterfaceOne using field one
   public DoSomeThingWithOne() { one.Hello(); }

   // do the stuff you want to do with an IInterfaceTwo using field two
   public DoSomeThingWithTwo() { two.World(); }
}
然后你就可以这样把东西连接起来:

var oneAndTwo = new Implementation();

var a = new UsingImplementation(oneAndTwo, oneAndTwo);

// operates on the first param (which is the same as the second)
a.DoSomeThingWithOne();

// operates on the second param (which is the same as the first)
a.DoSomeThingWithTwo();
看看IoC原则(控制反转)和依赖注入,你会发现更多类似于这个的解决方案


这样,您就不需要创建一个额外的接口来组合InterfaceOne和InterfaceTwo,二者。

遗憾的是,C#不支持这一点,因为它不适合C#接口的工作方式。是的,我支持。我的意思是,你不一定要有一个泛型类才能做到这一点,使这个解决方案比泛型类更通用。这种方法的一个困难,我在我的答案是,如果一个字段未声明为满足这些约束的类型(即使该字段包含一个事实上满足这些约束的对象),则很难调用具有此类约束的例程。对于变量来说,这不是一个特别的问题,但当集合中的项可能不共享任何公共基时,这会使持久化此类类型的集合变得非常困难。是的,通常唯一可能的解决方案是仅使用两个接口中的一个作为声明类型,并对第二个接口使用断言和强制转换。这是次优的,但生活并不完美。谢谢你,这告诉了我我需要知道的——我从来没有从区分“传入”和“静态”字段/成员的角度来看待它。像这样思考,我可以看到泛型是如何支持这一点的,但是“匿名”组合对编译器的要求可能有点太高了+1谢谢你;我所看到的这种模式似乎是这类问题的公认解决方案,使用隐式转换运算符时,它尽可能接近于可以以预期方式使用的内容。
var oneAndTwo = new Implementation();

var a = new UsingImplementation(oneAndTwo, oneAndTwo);

// operates on the first param (which is the same as the second)
a.DoSomeThingWithOne();

// operates on the second param (which is the same as the first)
a.DoSomeThingWithTwo();