接口通用层次结构

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'的隐式引用转换.

在这种情况下,如何正确使用通用接口?

Eri*_*ert 7

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.

这就是转换必须是非法的原因.

那你怎么能让这个合法呢?

代码代表,你不能,因为正如我刚才所示,它不是类型安全的.

你可以把它的法律通过标记Tout这样的:interface IB<out T>.但是,T在任何"输入上下文"中使用它是非法的.特别是,您不能拥有任何T具有setter 的类型的属性.如果我们制定了该限制,那么问题就会消失,因为a_val无法将其设置为实例,Orange 因为它是只读的.

这个问题在SO上经常被问到.有很多例子,请在C#中查找有关"协方差和逆变"的问题.