5

比如说,我有一堂课:

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,人们会期望 MyFoo 的 IEnumerable 可以被视为 IMyBar 的 IEnumerable。一个平凡的现实世界示例正在生成汽车列表,然后被告知这不是车辆列表。

这只是一个小烦恼,但如果有人能对此有所了解,我将不胜感激。

4

4 回答 4

14

这将在 C# 4.0 中工作!您所说的称为泛型协方差

同时,您可以使用Cast扩展方法

List<IMyBar> interfaceList = new List<IMyBar>(classList.Cast<IMyBar>());
于 2010-03-22T21:29:08.640 回答
3

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

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

于 2010-03-22T21:30:14.877 回答
3

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

.Net 4.0 根本不会改变这些类型的关联方式。它们仍将是仅通过专业化相关的两种完全不同的类型。它将做的是允许您编写了解专业化关系的方法,并且在某些情况下允许您在编写另一个时替换一个。

于 2010-03-22T21:37:08.920 回答
1

如果您想在 IEnumerables 之间进行转换(正如您在问题的标题中所写的那样)而不是在 Lists 之间进行转换(正如您在问题中所写的那样),您可以等待 c# 4.0 协方差特性。在此之前,您可以使用扩展方法。但我不会使用其他答案中提到的Cast 扩展方法,而是编写我自己的方法,该方法只能用于 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;
        }
    }
}

最终节点。网络框架 4.0似乎没有预编译器常量,否则我会添加

    #if DOTNET4
    [Obsolete("You can directly cast in C# 4.0.")]
    #endif
于 2010-03-22T22:36:57.443 回答