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