14

我有以下类/接口:

// 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?)

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

4

3 回答 3

45

好的,让我们AFish, IAwith IAnimal, BwithAquariumIB<T>with 替换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!

您可以将 Tiger 放入 foo - foo 被键入为可以包含任何动物的容器。但是您只能将鱼放入水族馆。由于您可以在 an 上合法执行的操作与您可以在 an 上执行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/

于 2012-04-27T14:41:16.960 回答
1

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

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

public interface IB<out T> where T : IA { }
于 2012-04-27T14:43:42.823 回答
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 类型的对象。错误!

于 2012-04-27T14:44:46.230 回答