【发布时间】:2013-01-15 07:19:44
【问题描述】:
给定以下类型:
public interface IPrimary{ void doBattle(); }
// an ISecondary "is" an IPrimary
public interface ISecondary : IPrimary { }
// An implementation of ISecondary is also an IPrimary:
internal class SecondaryImpl : ISecondary
{
// Required, since this is an IPrimary
public void doBattle(){ }
}
为什么我不能这样做?
List<IPrimary> list = new List<ISecondary>();
这会导致以下编译错误:
参数类型“System.Collections.Generic.List”不可分配给参数类型“System.Collections.Generic.List”
我了解该错误,并且知道有解决方法。我只是看不出为什么不允许这种直接转换的任何明确原因。 ISecondary 列表中包含的值毕竟应该是(通过扩展)IPrimary 类型的值。那么为什么 List<IPrimary> 和 List<ISecondary> 被解释为不相关的类型?
谁能解释清楚 C# 以这种方式设计的原因?
一个稍微扩展的例子:我在尝试做类似以下的事情时遇到了这个问题:
internal class Program
{
private static void Main(string[] args)
{
// Instance of ISecondary, and by extention, IPrimary:
var mySecondaryInstance = new SecondaryImpl();
// This works as expected:
AcceptImpl(mySecondaryInstance);
// List of instances of ISecondary, which are also,
// by extention, instances of IPrimary:
var myListOfSecondaries = new List<ISecondary> {mySecondaryInstance};
// This, however, does not work (results in a compilation error):
AcceptList(myListOfSecondaries);
}
// Note: IPrimary parameter:
public static void AcceptImpl(IPrimary instance){ }
// Note: List of type IPrimary:
public static void AcceptList(List<IPrimary> list){ }
}
【问题讨论】:
-
你想看“C#中的泛型协变”
-
Covariance and contravariance。
List<IPrimary> list = new List<ISecondary>();没有实际意义,即使你可以这样做。 -
@GrantThomas 好的,可能有点简化了;但是
someListOfTypePrimary.AddRange(someProvider.getListOftypeSecondary());呢?有什么理由不应该发生这种情况吗? -
我认为应该允许这样做,因为
AddRange采用IEnumerable<T>类型,它确实支持协方差-IEnumerable<ISecondary>可以在任何可以使用IEnumerable<IPrimary>的地方使用。