实现嵌套通用接口
我有以下类/接口:
// Model public class A : IA { } // ModelLogic public class B : IB { } // Model Interface public interface IA { } // ModelLogic Interface public interface IB where T : IA { }
我尝试使用以下代码创建一个新实例:
IB foo = new B();
我收到以下错误:
Cannot implicitly convert type 'B' to 'IB'. An explicit conversion exists (are you missing a cast?)
有人可以解释为什么这是不可能的?
好吧,让我们用Fish
取代A
,用IAnimal
代替IA
,用Aquarium
IAnimal
B
,用IContainer
代替IB
IContainer
。 我们将向IContainer
添加一个成员,并向IAnimal
添加第二个实现:
// Model public class Fish : IAnimal { } public class Tiger : IAnimal { } // ModelLogic public class Aquarium : IContainer { public Fish Contents { get; set; } } // Model Interface public interface IAnimal { } // ModelLogic Interface public interface IContainer where T : IAnimal { T Contents { get; set; } } IContainer foo = new Aquarium(); // Why is this illegal? foo.Contents = new Tiger(); // Because this is legal!
你可以将老虎放入foo – foo被输入为可容纳任何动物的容器 。 但是你只能将鱼放入水族馆。 由于您可以在Aquarium
上合法执行的操作与您在IContainer
上执行的操作不同 ,因此类型不兼容。
您想要的function称为通用接口协方差 ,它受C#4支持,但您必须向编译器certificate您永远不会将老虎放入您的鱼缸。 你想要做的是:
// Model public class A : IA { } // ModelLogic public class B : IB { } // Model Interface public interface IA { } // ModelLogic Interface public interface IB where T : IA { }
请注意IB
上的协方差注释。 这意味着T
只能用作输出 ,而不能用作输入。 如果T
只是一个输出,那么就没有人可以将老虎放入该鱼缸,因为没有“投入”财产或方法。
我在将这个function添加到C#时写了一些博客文章; 如果您对该function的设计注意事项感兴趣,请参阅:
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/
要修复代码,只需更改即可
public interface IB where T : IA { }
至
public interface IB where T : IA { }
当你有空接口时,不容易看到。 考虑在接口IB中有一个方法M:
public interface IB where T : IA { void M(T t); }
这是B的实现:
public class B : IB { public void M(A t) { // only object of type A accepted } }
然后你有对象C,它也实现了IA:
public class C : IA { }
所以,如果您的代码可以,那么您可以调用:
IB foo = new B(); foo.M(new C());
问题是B类只接受A类对象。错误!