2013-04-11 110 views
10

我想从一个只有在运行时才知道类型参数的泛型类中获得方法的MethodInfo如何查找使用强类型反射的泛型类方法的MethodInfo?

这是我如何会得到MethodInfo为一个通用的方法从非通用类:

class MyClass 
{ 
    public void MyMethod<T> (T arg) 
    { 
    } 
} 

static MethodInfo Resolve (Type type) 
{ 
    Expression<Action<MyClass, object>> lambda = (c, a) => c.MyMethod (a); 
    MethodCallExpression    call = lambda.Body as MethodCallExpression; 

    return call 
     .Method      // Get MethodInfo for MyClass.MyMethod<object> 
     .GetGenericMethodDefinition() // Get MethodInfo for MyClass.MyMethod<> 
     .MakeGenericMethod (type);  // Get MethodInfo for MyClass.MyMethod<int> 
} 

Resolve (typeof (int)).Invoke (new MyClass(), new object[] {3}); 

现在,如果我想尝试用一个通用类类似的东西:

class MyClass<T> 
{ 
    public void MyMethod (T arg) 
    { 
    } 
} 

static MethodInfo Resolve (Type type) 
{ 
    Expression<Action<MyClass<object>, object>> lambda = (c, a) => c.MyMethod (a); 
    MethodCallExpression      call = lambda.Body as MethodCallExpression; 

    return call 
     .Method    // Get MethodInfo for MyClass<object>.MyMethod 
     .SomeMagicMethod(); // FIXME: how can I get a MethodInfo 
          // for MyClass<T>.MyMethod where typeof (T) == type? 
} 

Resolve (typeof (string)).Invoke (new MyClass<string>(), new object[] {"Hello, World!"}); 

可能吗?

+0

因为'C .Meth'和'C .Meth'是风马牛不相及方法根据.NET类型系统,因为他们的'DeclaringType'这是棘手s是不同的。 – usr 2013-04-11 21:44:11

+0

你能解决你的解决方案代码吗?您正在使用'method'变量作为'MethodInfo'和'MethodInfo []'。甚至搜索数组匹配相同的变量。这是没有意义的。 – kjbartel 2015-09-03 04:36:08

+0

变量'method'确实应该是一个数组,但第二个搜索遍历包含解决方案,所以它只是一个错误。考虑再次阅读问题。 – r3c 2015-09-04 07:04:23

回答

2
public class MyClass<T> 
{ 
    public void MyMethod(T arg, bool flag) 
    { 
     Console.WriteLine("type: MyClass<{0}>, arg: {1}, flag:{2}", typeof(T), 
      arg.ToString(), flag); 
    } 
    public void MyMethod(T arg) 
    { 
     Console.WriteLine("type: MyClass<{0}>, arg: {1}", typeof(T), arg.ToString()); 
    } 
} 
public class GenericInvokeTest 
{ 
    static MethodInfo Resolve(Type type) 
    { 
     var name = ActionName<object>(x => (o) => x.MyMethod(o)); 
     var genericType = typeof(MyClass<>).MakeGenericType(new[] { type }); 
     MethodInfo genericTypeMyMethodInfo = genericType.GetMethod(name); // "MyMethod"); 
     genericTypeMyMethodInfo = genericType.GetMethod(name, new[] { type, typeof(bool) }); 
     return genericTypeMyMethodInfo; 
    } 
    public static void Test1() 
    { 
     Resolve(typeof(string)) 
      .Invoke(new MyClass<string>(), new object[] { "Hello, World!", true }); 
     // Resolve(typeof(string)) 
      .Invoke(new MyClass<string>(), new object[] { "Hello, World!" }); 
    } 
} 

要使它强类型的你应该简化,并使用不同的方法:

1)使用表达式获取动作/方法的name ...

var name = ActionName<object>(x => (o) => x.MyMethod(o)); 

2 )然后做不可避免的反射部分

var genericType = typeof(MyClass<>).MakeGenericType(new[] { type }); 
MethodInfo genericTypeMyMethodInfo = genericType.GetMethod(name); // "MyMethod"); 


其中 ActionName正在采用类似的方法。 OnPropertyChanged(x => x.Property)

public static string ActionName<T>(Expression<Func<MyClass<T>, Action<T>>> expression) 
{ 
    return GetMemberName(expression.Body); 
} 
public static string GetMemberName(Expression expression) 
{ 
    switch (expression.NodeType) 
    { 
     case ExpressionType.Lambda: 
      var lambdaExpression = (LambdaExpression)expression; 
      return GetMemberName(lambdaExpression.Body); 
     case ExpressionType.MemberAccess: 
      var memberExpression = (MemberExpression)expression; 
      var supername = GetMemberName(memberExpression.Expression); 
      if (String.IsNullOrEmpty(supername)) 
       return memberExpression.Member.Name; 
      return String.Concat(supername, '.', memberExpression.Member.Name); 
     case ExpressionType.Call: 
      var callExpression = (MethodCallExpression)expression; 
      return callExpression.Method.Name; 
     case ExpressionType.Convert: 
      var unaryExpression = (UnaryExpression)expression; 
      return GetMemberName(unaryExpression.Operand); 
     case ExpressionType.Parameter: 
      return String.Empty; 
     default: 
      throw new ArgumentException(
       "The expression is not a member access or method call expression"); 
    } 
} 
+0

谢谢,但重点仅仅是使用强类型的反射,而不是“GetMethod”或类似的方法,它不会在重构中生存。 – r3c 2013-04-12 08:08:57

+0

我没有看到这一点我猜:)我刚刚更新了答案。 – NSGaga 2013-04-12 12:16:41

+1

好主意,但不幸的是,它不适用于重载方法:它会在GetMethod调用中抛出一个“AmbiguousMatchException”,解决它将非常困难,因为它意味着重写大部分(破坏的)“GetMethod”内部逻辑。 – r3c 2013-04-12 12:30:03

1

工作液:

static MethodInfo Resolve (Type type) 
{ 
    Expression<Action<MyClass<object>, object>> lambda = (c, a) => c.MyMethod (a); 
    MethodCallExpression      call = lambda.Body as MethodCallExpression; 
    MethodInfo[]        methods; 
    Type          target; 

    target = call 
     .Method // Get MethodInfo for MyClass<object>.MyMethod 
     .DeclaringType // Get typeof (MyClass<object>) 
     .GetGenericTypeDefinition() // Get typeof (MyClass<>) 
     .MakeGenericType (type); // Get typeof (MyClass<T>) where typeof (T) == type 

    methods = target.GetMethods (BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); // We probably don't need static methods 

    return Array.Find (methods, (m) => m.MetadataToken == method.MetadataToken); // Find MyClass<T>.MyMethod where typeof (T) == type 
} 
相关问题