我想从泛型类中获取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 :(得分: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");
}
}
答案 1 :(得分: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
}