实现嵌套通用接口

Bry*_*ter 14 c# generics nested interface nested-generics

我有以下类/接口:

// 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 { }
Run Code Online (Sandbox Code Playgroud)

我尝试使用以下代码创建一个新实例:

IB<IA> foo = new B();
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

Cannot implicitly convert type 'B' to 'IB<IA>'. An explicit conversion exists (are you missing a cast?)
Run Code Online (Sandbox Code Playgroud)

有人可以解释为什么这是不可能的?

Eri*_*ert 43

好吧,让我们更换AFish,IAIAnimal,BAquarium,并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!
Run Code Online (Sandbox Code Playgroud)

你可以将一只老虎放入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 { }
Run Code Online (Sandbox Code Playgroud)

注意协方差注释IB.这out意味着T只能用作输出,而不能用作输入.如果T只是一个输出,那么没有人可以将老虎放入该鱼缸,因为没有"投入"财产或方法.

我在将这个功能添加到C#时写了一些博客文章; 如果您对该功能的设计注意事项感兴趣,请参阅:

http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/

  • @Sandeep:当你说你只想在输出位置使用T时,你在某个输入位置使用T. `Contents`是一个带有二传手的属性吗?如果是那么显然T正在输入位置使用,因此界面不能在T中变成协变. (3认同)