为什么采用IEnumerable <interface>的函数不接受IEnumerable <class>?</class> </interface>

时间:2010-03-22 21:27:39

标签: generics inheritance c#-3.0 ienumerable covariance

比方说,我有一个班级:

public class MyFoo : IMyBar
{
    ...
}

然后,我想使用以下代码:

List<MyFoo> classList = new List<MyFoo>();
classList.Add(new MyFoo(1));
classList.Add(new MyFoo(2));
classList.Add(new MyFoo(3));

List<IMyBar> interfaceList = new List<IMyBar>(classList);

但这会产生错误:

`Argument '1': cannot convert from 'IEnumerable<MyFoo>' to 'IEnumerable<IMyBar>' 

这是为什么?由于MyFoo实现了IMyBar,人们可以预期IEnumerable的MyFoo可以被视为IMyBar的IEnumerable。一个世俗的现实世界的例子是生产汽车列表,然后被告知它不是车辆列表。

这只是一个小小的烦恼,但如果有人能够对此有所了解,我会非常感激。

4 个答案:

答案 0 :(得分:14)

这将在C#4.0中运行!你所说的是泛型协方差

在此期间,您可以使用Cast extension method

List<IMyBar> interfaceList = new List<IMyBar>(classList.Cast<IMyBar>());

答案 1 :(得分:3)

这在.NET 4.0中受支持,但不是更早。

http://msdn.microsoft.com/en-us/library/dd799517%28VS.100%29.aspx

答案 2 :(得分:3)

澄清一下,它现在不起作用的原因是IEnumerable<MyClass>不会从IEnumerable<MyBar>继承。我再说一遍:派生类型的可枚举不会从基类型的可枚举继承。相反,两种类型都专门化IEnumerable<T>泛型类型。在.Net 3.5及更低版本中,它们除了特化之外没有其他关系(不是继承),在类型系统中是两种完全不同的类型。

.Net 4.0不会改变这些类型的相关方式。它们仍然是两种完全不同的类型,只能通过专业化来实现。它的作用是允许你编写了解专业化关系的方法,在某些情况下允许你在编写另一个时替换一个。

答案 3 :(得分:1)

如果你想在IEnumerables(正如你在问题的标题中所写)之间而不是在列表之间(如你在问题中所写的那样)之间进行投射,你可以等待c#4.0协方差特征。 在那之前,您可以使用扩展方法。 但是我不会使用其他答案中提到的Cast extension method,而是编写我自己的方法,它只能用于IEnumerable中的协方差转换。何时/如果您切换到C#4.0,您将很容易找到代码中转换为冗余的所有位置。

public static class cEnumerableExtensions
{
    public static IEnumerable<TResult> CovarianceConversion<TResult, TSource>(this IEnumerable<TSource> source)
        where TSource : TResult
    {
        foreach (var item in source)
        {
            yield return item;
        }
    }
}

最终节点。似乎有no precompiler constant for the netframework 4.0,否则我会添加

    #if DOTNET4
    [Obsolete("You can directly cast in C# 4.0.")]
    #endif