none
ジェネリックスメソッドの型パラメータにDictionaryで保持しているTypeを指定する方法 RRS feed

  • 質問

  • お世話になります。
    ジェネリックスメソッドをループ処理で呼ぶ際の型パラメータに、
    Dictionaryで保持しているTypeを使用したいのですが、可能でしょうか。

    以下、サンプルコードです。

    =========================================================================
    public class MainClass
    {
        //ジェネリックスメソッド
        public T[] TestMethod<T>() where T : base1, new()
        {
            var rtn = new T[1];

            return rtn;

        }
    }

    //基本クラス
    public class base1
    {
        //処理省略
    }

    // 派生クラスA
    public class ClassA:base1
    {
        //処理省略
    }

    // 派生クラスB
    public class ClassB:base1
    {
        //処理省略
    }

    //-----実際の処理部分-----
    class TestClass
    {
        void Test()
        {
            Dictionary<int, Type> ActDataKindCom = new Dictionary<int, Type>();
            ActDataKindCom.Add(1,typeof(ClassA));
            ActDataKindCom.Add(2,typeof(ClassB));

            for (int i = 1; i < 3; i++)
            {
                Type type = ActDataKindCom[i];
                MainClass.TestMethod<type>();
            }   
        }
    }

    =========================================================================

    上記のように、ディクショナリに型を保持しておいて、
    ジェネリックスメソッドの型パラメータに使用したいのですが、
    以下のようなエラーになります。

    型または名前空間名 'type' が見つかりませんでした。using ディレクティブまたはアセンブリ参照が不足しています。

    このような場合、ループしないで1個ずつメソッド呼び出し処理を書くしかないのでしょうか?

     

    2013年5月1日 2:39

回答

  • TestMethod<type>の記述ができたとして、そのtypeがbase1クラスから派生してるか、new()を持っているかはコンパイル時に決定できませんよね。

    Dictionary<int, Action>

    として、

    ActDataKindCom.Add(1, () => MainClass.TestMethod<ClassA>());

    のようにデリゲートを登録し(ラムダ式なのはTestMethod<T>がT[]を返すのでActionにできないため)、

    ActDataKindCom[i]();

    と呼び出す方法は考えられます。

    • 回答としてマーク yurubon 2013年5月1日 7:06
    2013年5月1日 3:01
  • もう解決されたようですが、たまにこの手の問題を見かけました。参考になるページをご紹介しておきます。

    Type オブジェクトを使ってジェネリックメソッドを呼び出す方法
    http://d.hatena.ne.jp/griefworker/20101227/call_generic_method


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク yurubon 2013年5月1日 11:56
    2013年5月1日 7:39
    モデレータ

すべての返信

  • TestMethod<type>の記述ができたとして、そのtypeがbase1クラスから派生してるか、new()を持っているかはコンパイル時に決定できませんよね。

    Dictionary<int, Action>

    として、

    ActDataKindCom.Add(1, () => MainClass.TestMethod<ClassA>());

    のようにデリゲートを登録し(ラムダ式なのはTestMethod<T>がT[]を返すのでActionにできないため)、

    ActDataKindCom[i]();

    と呼び出す方法は考えられます。

    • 回答としてマーク yurubon 2013年5月1日 7:06
    2013年5月1日 3:01
  • C#のgenericsはコンパイル時に決定できるの必要があります。typeは変数であり、実行時に変化するため使用できません。

    C# 2.0より前にはgenericsがなく、それでも必要なことは記述できたわけで、今回のように変数を使う場合は同じようになります。
    # 他にも方法はありますが。

    public object TestMethod(Type type){
      return Array.CreateInstance(type, 1);
    }

    とでもすることでしょうか。C# 4.0以降であれば配列の共変性が使えますが。

    2013年5月1日 3:52
  • Hongliang様

    早速のご回答有難うございます。

    教えていただたいた通り、Actionにする事で、希望のメソッドを実行する事が出来ました。

    さらに質問になって申し訳ないのですが、
    Actionで実行したメソッドのリターン値を取得するにはどうしたら良いのでしょうか・・・?

    var a = ActDataKindCom[i]();

    のように書いてもエラーになってしまい・・・。

    (私のサンプルソースが戻り値を取得しないソースになっていて、申し訳ありません。)

     

    佐祐理様

    なるほど、納得しました。Typeも変数になってしまうのですね。

    今回はすでにdllとして作られているメソッドを呼び出す方法を探していたので
    Hongliang様の方法を使わせて頂く事にしましたが、
    とても勉強になりました。有難うございました。

     

    2013年5月1日 4:49
  • なるほど、納得しました。Typeも変数になってしまうのですね。

    横から失礼しますが、Typeは変数ではありません。

    typeは変数です。

    2013年5月1日 4:53
  • 横から失礼しますが、Typeは変数ではありません。

    typeは変数です。

    aviator__様、大変失礼しました。

    私のぼんやりした理解でコメント書いてしまい、誤解を招くような文章になってしまいました。

    >皆様

    戻り値を取得する為の方法としてFuncを使用すればよいことがわかりました。

    お騒がせしました。

    みなさま大変お世話になりました。有難うございました。

    2013年5月1日 7:06
  • もう解決されたようですが、たまにこの手の問題を見かけました。参考になるページをご紹介しておきます。

    Type オブジェクトを使ってジェネリックメソッドを呼び出す方法
    http://d.hatena.ne.jp/griefworker/20101227/call_generic_method


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク yurubon 2013年5月1日 11:56
    2013年5月1日 7:39
    モデレータ