none
List<T>型のT型を暗黙的に型変換できない理由について RRS feed

  • 質問

  • こんにちは。
    C#のプログラムを書いていて、次のコードでListコレクションの変換がエラーになる理由がよくわかりません。

    意見

    class Program
        {
            class Test { 
                int a { get; set; } 
                int b { get; set; } 
            }
    
            static void Main(string[] args)
            {
                var tests = new List<Test>();
    
                var obj = new Test() as object; // OK
    
                List<dynamic> t1 = tests;   // ERROR
                List<object> t2 = tests;    // ERROR
                List<Test> t3 = tests;      // OK
            }
        }
    エラー		型 'System.Collections.Generic.List<_Test.Program.Test>' を型 'System.Collections.Generic.List<object>' に暗黙的に変換できません。	
    

    自分はどの変数宣言も全部問題なく通ると思っていましたが、t1、t2はダメなようです。
    たしかに、このList<Object>なんかはジェネリックのコードとして良くない気はするのですが、それでコンパイルエラーになっているのでしょうか。

    また、List<Test>の書き方以外でコンパイルエラーにならない変数宣言のしかたはあるのでしょうか。

    わかる方いましたら教えてください。
    よろしくお願いします。

    2014年12月10日 4:58

回答

  • 参考に。

    ジェネリックの共変性と反変性
    http://msdn.microsoft.com/ja-jp/library/dd799517(v=vs.110).aspx

    • 回答としてマーク ichiethel 2014年12月10日 7:19
    2014年12月10日 5:07
  • 参考ありがとうございます。
    少しわかったような気がします。

    IEnumerable<Derived> d = new List<Derived>();
    IEnumerable<Base> b = d;
    IEnumerable<Test> d = new List<Test>();
    IEnumerable<Object> b = d;

    Tの部分がDerivedのコードは、参考から参照したコードです。以下のようにありました。

    共変の型パラメーターでは、次のコードで示されているように、通常のポリモーフィズム (C# プログラミング ガイド)と非常によく似た代入を行うことができます。

    参考のコードのTの部分をTestに変えたコードを書いてみたら、コンパイルに成功するようになりました。

    また、一部のうまくできないと思っていましたが、よく見るとClassじゃなくてStructでした。値型だからできなかったです。

    C#のStruct型は、Interfaceを継承していたり、Get/SetプロパティやToStringをOverrideするものが定義できてしまうのですね。ここでもClassと勘違いして、問題が見抜けなくて時間がかかりました。結果的には、Structは不変というのも合わせて理解できてある意味よかったです。

    なかなか理解できませんでしたが、少し理解できました。
    ありがとうございました。




    • 編集済み ichiethel 2014年12月10日 7:06
    • 回答としてマーク ichiethel 2014年12月10日 7:19
    2014年12月10日 7:03

すべての返信

  • 参考に。

    ジェネリックの共変性と反変性
    http://msdn.microsoft.com/ja-jp/library/dd799517(v=vs.110).aspx

    • 回答としてマーク ichiethel 2014年12月10日 7:19
    2014年12月10日 5:07
  • 参考ありがとうございます。
    少しわかったような気がします。

    IEnumerable<Derived> d = new List<Derived>();
    IEnumerable<Base> b = d;
    IEnumerable<Test> d = new List<Test>();
    IEnumerable<Object> b = d;

    Tの部分がDerivedのコードは、参考から参照したコードです。以下のようにありました。

    共変の型パラメーターでは、次のコードで示されているように、通常のポリモーフィズム (C# プログラミング ガイド)と非常によく似た代入を行うことができます。

    参考のコードのTの部分をTestに変えたコードを書いてみたら、コンパイルに成功するようになりました。

    また、一部のうまくできないと思っていましたが、よく見るとClassじゃなくてStructでした。値型だからできなかったです。

    C#のStruct型は、Interfaceを継承していたり、Get/SetプロパティやToStringをOverrideするものが定義できてしまうのですね。ここでもClassと勘違いして、問題が見抜けなくて時間がかかりました。結果的には、Structは不変というのも合わせて理解できてある意味よかったです。

    なかなか理解できませんでしたが、少し理解できました。
    ありがとうございました。




    • 編集済み ichiethel 2014年12月10日 7:06
    • 回答としてマーク ichiethel 2014年12月10日 7:19
    2014年12月10日 7:03