2010-12-14 18 views
9

汎用メソッドの2つのオーバーロードを含むこの型を持っています。私はリフレクションを使用してオーバーロードの1つ(Func<T>パラメータ)を取得するのが好きです。しかし問題は、Type.GetMethod(string, Type[])メソッドを提供するための正しいパラメータタイプが見つからないことです。ここで汎用メソッドの正しいオーバーロードのMethodInfoの取得

は私のクラスの定義です:

public class Foo 
{ 
    public void Bar<T>(Func<T> f) { } 
    public void Bar<T>(Action<T> a) { } 
} 

そして、これは私は残念ながら大成功せず、作ってみたものです:

[TestMethod] 
public void Test1() 
{ 
    Type parameterType = typeof(Func<>); 

    var method = typeof(Foo).GetMethod("Bar", new Type[] { parameterType }); 

    Assert.IsNotNull(method); // Fails 
} 

にはどうすればいいの一般的な方法のMethodInfoを得ることができます私はパラメータを知っていますか?あなたはMethodInfo.MakeGenericMethod.

を使用して、具体的な型を指定する必要があり

答えて

9

なぜ表現木を使用しませんか?これにより、はるかに簡単になります。

public static MethodInfo GetMethod<T>(
    Expression<Action<T>> methodSelector) 
{ 
    var body = (MethodCallExpression)methodSelector.Body; 
    return body.Method;  
} 

[TestMethod] 
public void Test1() 
{ 
    var expectedMethod = typeof(Foo) 
     .GetMethod("Bar", new Type[] { typeof(Func<>) }); 

    var actualMethod = 
     GetMethod<Foo>(foo => foo.Bar<object>((Func<object>)null) 
     .GetGenericMethodDefinition(); 

    Assert.AreEqual(expectedMethod, actualMethod); 
} 
+0

うわー。それはクールです。よく働く!そして少しのコード。 – Anne

1

しかし、私はあなたがオーバーロードされた汎用的なメソッドを持っているときにMakeGenericMethodを呼び出すために右のタイプを取得することは容易ではないことを、指摘しなければなりません。ここで

は一例です。

var method = typeof(Foo) 
       .GetMethods() 
       .Where(x => x.Name == "Bar") 
       .Where(x => x.IsGenericMethod) 
       .Where(x => x.GetGenericArguments().Length == 1) 
       .Where(x => x.GetParameters().Length == 1) 
       .Where(x => 
        x.GetParameters()[0].ParameterType == 
        typeof(Action<>).MakeGenericType(x.GetGenericArguments()[0]) 
       ) 
       .Single(); 

method = method.MakeGenericMethod(new Type[] { typeof(int) }); 

Foo foo = new Foo(); 
method.Invoke(foo, new Func<int>[] {() => return 42; }); 
+0

これは役に立ちません。彼は開いたインスタンスを得ることができません。 – SLaks

+0

私に例を教えてもらえますか? – Anne

+0

@SLaks:はい、可能です。私は例を投稿します。 – jason

1

私はあなたが直接GetMethodを使用してこれを行うことができますとは思いません。私はその後、あなたがBarと呼ばれるすべてのメソッドを反復処理する必要があります疑い:この方法は、1つの通常のパラメータを持っていることの方法は、1種類のパラメータを持っていることを

  • チェック
  • チェック
  • に型パラメータを使用しますFunc<T>typeof(Func<>).MakeGenericType)を作成し、パラメータの種類がそれと一致することを確認します。

LINQはこの種のものに適しています。完全なサンプル:

using System; 
using System.Reflection; 
using System.Linq; 

public class Foo 
{ 
    public void Bar<T>(Func<T> f) { } 
    public void Bar<T>(Action<T> a) { } 
} 

class Test 
{ 
    static void Main() 
    { 
     var methods = from method in typeof(Foo).GetMethods() 
         where method.Name == "Bar" 
         let typeArgs = method.GetGenericArguments() 
         where typeArgs.Length == 1 
         let parameters = method.GetParameters() 
         where parameters.Length == 1 
         where parameters[0].ParameterType == 
          typeof(Func<>).MakeGenericType(typeArgs[0]) 
         select method; 

     Console.WriteLine("Matching methods..."); 
     foreach (var method in methods) 
     { 
      Console.WriteLine(method); 
     } 
    } 
} 

は、基本的にはジェネリック医薬品と反射が、私は

4

驚くべきことに、それはあなたが見つけるまでの方法よりGetMethods()とループを呼び出す必要がありますように見える:(怖い、組み合わせて、本当に厄介です1あなたが望むたとえば

var yourMethod = typeof(Foo).GetMethods() 
    .First(m => m.Name == "Bar" 
      && m.GetParameters().Length == 1 
      && m.GetParameters()[0].ParameterType.ContainsGenericParameters 
      && m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(Func<>)); 
+0

それは動作します。ありがとう。 – Anne

0

は、あなただけのだけのGetMethodとと格闘う - あなたは林に沿って何かを試みることができます。のです。

var method = (from m in typeof(Foo).GetMethods() 
    where 
    m.IsGenericMethodDefinition == true && 
    m.Name == "Bar" && 
    m.GetParameters().Length > 0 && 
    m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == parameterType 
    select m).FirstOrDefault();