13

以下代码无法编译(使用 VS2010),我不明白为什么。编译器应该能够推断出与List<TestClass>'兼容'(抱歉没有更好的词)IEnumerable<ITest>,但不知何故它不。我在这里想念什么?


interface ITest {
    void Test();
}


class TestClass : ITest {
    public void Test() {
    }
}

class Program {
    static void Test(IEnumerable<ITest> tests) {
        foreach(var t in tests) {
            Console.WriteLine(t);
        }
    }
    static void Main(string[] args) {
        var lst = new List<TestClass>();

        Test(lst); // fails, why?

        Test(lst.Select(t=>t as ITest)); //success

        Test(lst.ToArray()); // success
    }
}

编译器给出两个错误:

  1. 'ConsoleApplication1.Program.Test(System.Collections.Generic.IEnumerable<ConsoleApplication2.ITest>)' 的最佳重载方法匹配有一些无效参数

  2. 参数 1:无法从 'System.Collections.Generic.List<ConsoleApplication2.TestClass>' 转换为 'System.Collections.Generic.IEnumerable<ConsoleApplication2.ITest>'

4

3 回答 3

8

您尝试做的事情称为协方差- 从较窄的类型 (TestClass) 转换为较宽的类型 (ITest)。这是你一直习惯的东西,例如,当你从浮点数转换为双精度数时会发生这种情况。

不幸的是,.Net 3.5 及更低版本不支持泛型类中的协方差。

.Net 4.0 现在确实支持泛型中的协变(和逆变),前提是这些泛型类是使用out协变类型和in逆变类型的关键字编译的。IEnumerable在 .Net 4.0 中被定义为协变。如果您右键单击IEnumerable类型并单击“转到定义”,您将看到:

public interface IEnumerable<out T> : IEnumerable

如果您使用的是 VS2010,则需要确保您的项目面向 .net 4.0。这可以从项目属性中更改。右键单击项目,选择属性,转到“应用程序”选项卡并检查“目标框架”是否适用于 .Net 4。

MSDN 有更多信息

于 2010-05-20T09:06:00.053 回答
2

这与方差(协方差和逆变)有关;查看这篇文章和 Jon Skeet 的回答

于 2010-05-20T08:54:52.400 回答
1

检查项目框架的目标版本。此代码仅适用于 .NET 4 。

于 2010-05-20T08:57:44.827 回答