2010-12-14 31 views
9

Tôi có loại này có chứa hai quá tải của một phương pháp chung. Tôi muốn lấy một trong những quá tải (với tham số Func<T>) bằng cách sử dụng sự phản chiếu. Tuy nhiên, vấn đề là tôi không thể tìm thấy kiểu tham số chính xác để cung cấp phương thức Type.GetMethod(string, Type[]) với.Lấy MethodInfo của quá tải chính xác của một phương pháp chung

Dưới đây là định nghĩa lớp của tôi:

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

Và đây là những gì tôi đã đưa ra, không may mà không succes:

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

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

    Assert.IsNotNull(method); // Fails 
} 

Làm thế nào tôi có thể nhận được MethodInfo của một phương pháp chung của mà tôi biết các thông số?

Trả lời

9

Tại sao bạn không sử dụng cây biểu thức? Điều này giúp việc này trở nên dễ dàng hơn nhiều:

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

Thật tuyệt vời.Hoạt động tuyệt vời! Và quá ít mã. – Anne

1

Bạn cần phải xác định một loại bê tông sử dụng MethodInfo.MakeGenericMethod.

Tuy nhiên, tôi phải chỉ ra, rằng nhận được đúng loại để gọi MakeGenericMethod trên là không dễ dàng khi bạn có một phương pháp chung chung quá tải.

Dưới đây là một ví dụ:

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

Điều đó sẽ không hữu ích. Anh ta không thể có được ví dụ mở. – SLaks

+0

Bạn có thể chỉ cho tôi một ví dụ không? – Anne

+0

@SLaks: Vâng, điều đó là có thể. Tôi sẽ đăng một ví dụ. – jason

1

tôi không nghĩ bạn có thể làm điều này trực tiếp sử dụng GetMethod. Tôi nghi ngờ bạn sẽ phải lặp lại trên tất cả các phương pháp gọi là Bar, sau đó:

  • Kiểm tra xem phương pháp này có tham số một loại
  • Kiểm tra xem phương pháp này có một tham số bình thường
  • Sử dụng kiểu tham số để tạo một Func<T> (với typeof(Func<>).MakeGenericType) và kiểm tra xem loại tham số có khớp với điều đó hay không.

LINQ phù hợp cho loại điều này. Toàn bộ mẫu:

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

Về cơ bản Generics và phản ánh là thực sự khó chịu kết hợp, tôi sợ :(

4

Đáng ngạc nhiên, có vẻ như bạn sẽ cần phải gọi GetMethods() và vòng hơn các phương pháp cho đến khi bạn tìm thấy một trong những bạn muốn

Ví dụ:

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

Nó hoạt động. Cảm ơn. – Anne

0

bạn sẽ phải vật lộn với chỉ với chỉ GetMethod - bạn có thể thử một cái gì đó dọc theo lin. es;

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(); 
Các vấn đề liên quan