Ale*_*oto 4 c# generic-interface
我有一些通用接口相互链接.
public interface IA
{
int val { get; set; }
}
public interface IB<T> where T:IA
{
T a_val { get; set; }
}
public interface IC<T> where T : IB<IA>
{
T b_val { get; set; }
}
public class a:IA
{
public int val { get; set; }
}
public class b:IB<a>
{
public a a_val { get; set; }
}
public class c:IC<b>
{
public b b_val { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
对于最后一节课c,我有一个错误:
类型'b'不能用作通用类型或方法'IC'中的类型参数'T'.没有从'b'到'IB'的隐式引用转换.
在这种情况下,如何正确使用通用接口?
Tin IC<T>必须是一个IB<IA>.你给了它一个IB<A>.您无法保证IB<A>可以将其用作IB<IA>仅仅因为A工具IA.
以这种方式思考:如果IB<T>意思是"我可以吃任何类型的东西",IA意思是"我是一个水果",A意思是"苹果",那就IB<IA>意味着"我可以吃任何水果",IB<A>意思是"我可以吃任何东西"苹果".如果一些代码想要给你喂香蕉和葡萄,那么它需要一个IB<IA>,而不是一个IB<A>.
让我们假设IB<A>可以转换为IB<IA>并看出出了什么问题:
class AppleEater : IB<Apple>
{
public Apple a_val { get; set; }
}
class Apple : IA
{
public int val { get; set; }
}
class Orange : IA
{
public int val { get; set; }
}
...
IB<Apple> iba = new AppleEater();
IB<IA> ibia = iba; // Suppose this were legal.
ibia.a_val = new Orange(); // ibia.a_val is of type IA and Orange implements IA
Run Code Online (Sandbox Code Playgroud)
现在我们设置iba.val,这是类型的属性,Apple以引用类型的对象Orange.
这就是转换必须是非法的原因.
那你怎么能让这个合法呢?
代码代表,你不能,因为正如我刚才所示,它不是类型安全的.
你可以把它的法律通过标记T为out这样的:interface IB<out T>.但是,T在任何"输入上下文"中使用它是非法的.特别是,您不能拥有任何T具有setter 的类型的属性.如果我们制定了该限制,那么问题就会消失,因为a_val无法将其设置为实例,Orange 因为它是只读的.
这个问题在SO上经常被问到.有很多例子,请在C#中查找有关"协方差和逆变"的问题.