实现嵌套通用接口

时间:2012-04-27 14:32:44

标签: c# generics interface nested 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 { }

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

IB<IA> foo = new B();

我收到以下错误:

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

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

3 个答案:

答案 0 :(得分:43)

好的,我们将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!

Aquarium

你可以将老虎放入foo - foo被输入为可以包含任何动物的容器。但你只能把鱼放入水族馆。由于您在IContainer<IAnimal>上合法执行的操作与<{1}}上可执行的操作不同,因此类型不兼容。

您想要的功能称为通用接口协方差,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/

答案 1 :(得分:1)

要修复您的代码,只需更改

即可
public interface IB<T> where T : IA { }

public interface IB<out T> where T : IA { }

答案 2 :(得分:0)

当你有空接口时,不容易看到。考虑在接口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类型的对象。错误!