C# 我是否可以将成员定义/约束为实现两个接口,而不使用泛型?
下面的代码显示了我想做什么;也就是说,我想约束一个对象,这样它就可以作为使用IInterfaceOne或IInterfaceTwo的各种方法的参数,而这两种方法都不能从另一个继承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
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();