实现嵌套泛型接口

本文关键字:泛型接口 嵌套 实现 | 更新日期: 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换成FishIA换成IAnimalB换成AquariumIB<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 类型的对象。 错误!