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
    }
}

コンパイラは次の 2 つのエラーを返します。

  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) への変換です。これは、常に慣れているものです。たとえば、float から double に変換するときに発生します。

残念ながら、.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 に答える