我使用Reflection从泛型方法中检索methodInfo:
public abstract class BaseIdea {}
public class ModuleBaseLogic {
public void Sponsor<T>(int id) {
// Do something
}
}
public class Caller {
protected static MethodInfo GetMethod<T>(Expression<Action<T>> expr)
{
return ((MethodCallExpression)expr.Body).Method.GetGenericMethodDefinition();
}
public Caller() {
MethodInfo method = GetMethod<ModuleBaseLogic>(q => q.Sponsor<object>(id));
}
}
这很好用。但是,如果该方法具有以下约束:
public void Sponsor<T>(int id) where T : BaseIdea, new() {
// Do something
}
q.Sponsor<object>
(在Caller里面)不编译:
类型“对象”不能用作通用类型或方法“ModuleBaseLogic.Sponsor(int)”中的类型参数“T”。没有从“对象”到“BaseIdea”的隐式引用转换。
我尝试用q.Sponsor<BaseIdea>
替换它,但这也不起作用
这应该工作到目前为止:
public abstract class BaseIdea {}
public class ConcreteIdea : BaseIdea {}
public class ModuleBaseLogic {
public void Sponsor<T>(int id)
where T : BaseIdea, new()
{
// Do something
}
}
public class Caller {
protected static MethodInfo GetMethod<T>(Expression<Action<T>> expr)
{
return ((MethodCallExpression)expr.Body).Method.GetGenericMethodDefinition();
}
public Caller() {
int id = 1;
MethodInfo method = GetMethod<ModuleBaseLogic>(q => q.Sponsor<ConcreteIdea>(id));
}
}
为了给出一些解释:像Jon Skeet提到的对象不能是具有任何通用约束的任何方法的通用参数。 BaseIdea不能是通用参数,因为它是抽象的,这通常是基类所必需的。最简单的Parameter是一个具体的类,它派生自BaseIdea,它是用我的ConcreteIdea-class给出的。正如kara所提到的,new()约束也需要一个无参数构造函数,它也可以是隐式构造函数(默认构造函数)。
这里有一些例子,如果你有一个where T : SomeClass, new()
,什么是允许的,什么不是
public abstract class MyBaseClass { }
public class MyClass : MyBaseClass { }
public class MyClass2 : MyBaseClass
{
public MyClass2(int x)
{
}
}
public class SomeOtherClass { }
public static void MyMethod<T>() where T : MyBaseClass, new() { }
public static void Main(string[] args)
{
MyMethod<MyBaseClass>(); // Does not work because MyBaseClass is abstract
MyMethod<MyClass>(); // works because T is MyClass, which is derived from MyBaseClass
MyMethod<MyClass2>(); // Doesn't work because it doesn't have a Std.Constructor "MyClass2()" it has a constructor with parameters "MyClass2(int x)"
MyMethod<SomeOtherClass>(); // Doesn't work because T is SomeOtherClass, and it's not derived from MyBaseClass.
}
另一种方法是使用一个表达式,通过使用nameof()
运算符确定方法的名称,然后实际执行此表达式。
public class Caller
{
protected static MethodInfo GetMethod<T>(Expression<Func<T, string>> expr) where T: class
{
// Execute the expression. We will get the method name.
string methodName = expr.Compile()(null);
// Return generic method information by name of the method
return typeof(T).GetMethod(methodName);
}
public Caller()
{
MethodInfo method = GetMethod<ModuleBaseLogic>(m => nameof(m.Sponsor));
}
}
注意:当使用相同名称的方法有多个重载时,这将不起作用。