2013-02-05 19 views
8

閉じた/構築されたジェネリックメソッドに引数値をどうやって渡すのですか?ジェネリック引数の型と値をジェネリックメソッドに渡す

私はリフレクションに触れていないので、しばらくしています。これは私の後ろにあったものでした。

class Program 
{ 
    static void Main(string[] args) 
    { 
     new ConcreteFoo().GenericMethod<int>(5); 
     Console.ReadKey(); 
    } 
} 

class ConcreteFoo 
{ 
    public void GenericMethod<Q>(Q q) 
    { 
     var method = MethodInfo.GetCurrentMethod();  
     var parameters = method.GetParameters();  
     if (parameters.Length > 0) 
      foreach (var p in parameters) 
       Console.WriteLine("Type: {0}", p.ParameterType); 

     // That still prints Q as the type. 
     // I've tried GetGenericArguments as well. No luck.     
     // I want to know: 
     // 1) The closed type, i.e. the actual generic argument supplied by the caller; and 
     // 2) The value of that argument 
    } 

    public void GenericMethodWithNoGenericParameters<Q>() 
    { 
     // Same here 
    } 
} 

class GenericFoo<T> 
{ 
    public void NonGenericMethod(T t) { /* And here*/ } 
    public void GenericMethod<Q>(Q q) { /* And here */ } 
} 

UPDATE

この質問は不条理ので、アスカーによって閉鎖されています。彼はC#プログラマーであることが判明した場合、子供たちにどのように愚かなパパがいるかを示すために、それを保持したいと考えています。

+3

'q.GetType()'を使用できない特定の理由はありますか? –

+5

'typeof(Q)'は、現在のメソッドのランタイム提供型を提供します。もしそれがあなたが求めているものであれば... –

+6

上記の2つのコメントの違いを明確にするために: 'q.GetType()'はオブジェクトの実際の型を取得します。つまり、サブクラスか実装'Q'がインターフェースの場合)。 'GenericMethod(1)'( 'Q'が 'Object')または' GenericMethod(1) '(' Q'は明示的に '' GenericMethod 'Int32')に代わって –

答えて

8

短い答えはtypeof(Q)です。 (あなたは、これらのタイプを列挙することはできませんし、あなたがそれらを特異的に記述しなければならない理由を説明しようとする)

長い答えは、このように書きます:

(それはクラスの宣言のものより、より汎用的である)それぞれの汎用的な方法で対応しています(これまでに)触れられたすべての特定化のための個別のMethodInfoインスタンスと、「テンプレート」/公開メソッドのための別のMethodInfo。

あなたが欲しいものを得るためにこれを使用することができます:

class ConcreteFoo {  
    public void GenericMethod<Q>(Q q) { 
    var method = MethodInfo.GetCurrentMethod(); 
    var closedMethod = method.MakeGenericMethod(typeof(Q)); 

    // etc 
    } 
} 

それはなぜですか? これは、リフレクションの「列挙演算」が閉じられた記述を参照するMethodInfoインスタンスを返さないためです。

あなたがそうのようなConcreteFooによって宣言された静的メソッド列挙した場合:

var atTime1 = typeof(ConcreteFoo).GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); 

ConcreteFoo.GenericMethod(true); 

var atTime2 = typeof(ConcreteFoo).GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); 

をあなたは同じ結果が得られます。 GenericMethodおよびそれに関連する特殊化については、GenericMethod(オープンバリアント)に関連付けられたリフレクションオブジェクトのみを取得します。

atTime2には、新しく作成されたGenericMethod <bool>を参照する追加のMethodInfoは含まれません。

しかし、それは本当に悪いことではありません、今ですか? GetMethods()は一貫性のある結果を返す必要があり、その結果は時間とともに変化しません。それは、「ナビゲーション」の操作だとなると 一般的な方法の代数は、実際には非常にいいです:

  1. すべてオープンMethodInfosがIsGenericMethod =真とIsGenericMethodDefinition =真
  2. すべて閉じMethodInfosを持っている=真IsGenericMethodているとIsGenericMethodDefinition = false
  3. 閉じたMethodInfoで.GetGenericMethodDefinition()を呼び出すと、開いているものが得られます
  4. 呼び出してください。MakeGenericTypeあなたは(これらの型が何であるかの文法的に意識することなく、どこで句を尊重していないため、例外を受信する可能性を)したいものを閉じたものは何でも得るオープンMETHODINFOに([]の種類を入力しparamsは)

同じことは、現在のスレッドの観点から(というよりもアセンブリとタイプのものから)来る反射操作のために行くん:

MethodBase MethodInfo.GetCurrentMethod() 

StackTrace trace = new StackTrace(); 
IEnumerable<MethodBase> methods = from frame in trace.GetFrames() 
            select frame.GetMethod(); 

ん(存在する場合) の実際のクローズドバリアントを実際に閉じているか、現在の呼び出しスタック全体にわたって返します。 GetCurrentMethod の場合には、あなたが簡単にあなたができる、GetCurrentMethodプラスMakeGenericMethodプラス文法的に利用可能typeof演算(何でも)でそれを置き換えることができながら、ので、あなたの質問には、不合理ではないようにして

あなたの発信者についてそれを言ってはいけません。

ですから、ジェネリックでないメソッドの場合は、スタックを常に見て、それらのメソッドのパラメータタイプが何であるかを正確に知ることができます。お互いに呼び出され、最終的にあなたのものを呼び出すメソッドが呼び出されました...しかし、一般的なもの(実際には本当に閉じていますが、私はそれを実行し、別のものを呼び出す一般的なメソッドは、 )はオープンなものです)、そのようなメソッドのローカル変数の値を知ることができないように、パラメータの型を見つけることはできません(決定的ですが、それはパフォーマンスの大きな欠陥になります可能性)。

+0

私はちょうど今この答えを見ました。私は過去の質問に対する答えのタブを維持するのには大したことではありません。そのような精巧な答えをどうもありがとう。私は明日それを読むつもりです、そして、私は緑のcheckieがあなたのところに来るのを見ることができます。 :-) –

関連する問題