C# 使用反射调用带约束的泛型方法

C# 使用反射调用带约束的泛型方法,c#,generics,reflection,constraints,C#,Generics,Reflection,Constraints,我使用反射从泛型方法检索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<Act

我使用反射从泛型方法检索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));
  }
}
公共抽象类BaseIdea{}
公共类模块逻辑{
公共无效赞助商(int id){
//做点什么
}
}
公共类调用者{
受保护的静态MethodInfo GetMethod(表达式表达式表达式)
{
return((MethodCallExpression)expr.Body.Method.GetGenericMethodDefinition();
}
公共调用方(){
MethodInfo method=GetMethod(q=>q.赞助商(id));
}
}
这个很好用。但是,如果该方法具有以下约束:

public void Sponsor<T>(int id)  where T : BaseIdea, new() {
  // Do something
}
public void赞助商(int id),其中T:BaseIdea,new(){
//做点什么
}
q.赞助商
(调用方内部)未编译:

类型“object”不能用作泛型中的类型参数“T” 类型或方法“ModuleBaseLogic.赞助人(int)”没有隐式 从“object”到“BaseIdea”的引用转换


我试着用
q.shandor
替换它,但这也不起作用

这里有一些例子,如果你有一个
其中t:SomeClass,new()

公共抽象类MyBaseClass{}
公共类MyClass:MyBaseClass{}
公共类MyClass2:MyBaseClass
{
公共MyClass2(int x)
{
}
}
公共类SomeOtherClass{}
公共静态void MyMethod(),其中T:MyBaseClass,new(){}
公共静态void Main(字符串[]args)
{
MyMethod();//不起作用,因为MyBaseClass是抽象的
MyMethod();//之所以有效,是因为T是MyClass,它是从MyBaseClass派生的
MyMethod();//不起作用,因为它没有标准构造函数“MyClass2()”它有一个参数为“MyClass2(int x)”的构造函数
MyMethod();//不起作用,因为t是另一个类,并且它不是从MyBaseClass派生的。
}

到目前为止,这应该是可行的:

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));
  }
}
公共抽象类BaseIdea{}
公共类ConcreteIdea:BaseIdea{}
公共类模块逻辑{
公共无效赞助商(int id)
其中T:BaseIdea,new()
{
//做点什么
}
}
公共类调用者{
受保护的静态MethodInfo GetMethod(表达式表达式表达式)
{
return((MethodCallExpression)expr.Body.Method.GetGenericMethodDefinition();
}
公共调用方(){
int-id=1;
MethodInfo method=GetMethod(q=>q.赞助商(id));
}
}
给一点解释: 像Jon Skeet提到的对象不能是任何具有任何泛型约束的方法的泛型参数。 BaseIdea不能是泛型参数,因为它是抽象的,基类通常需要抽象。 最简单的可能参数是一个具体的类,它派生自BaseIdea,它与我的ConcreteIdea类一起给出。
正如kara提到的,新的()约束还需要一个无参数构造函数,也可以是隐式构造函数(默认构造函数)。

另一种方法是使用一个表达式,通过使用
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));
    }
}
公共类调用者
{
受保护的静态MethodInfo GetMethod(表达式expr),其中T:class
{
//执行表达式。我们将获得方法名称。
string methodName=expr.Compile()(空);
//按方法名称返回泛型方法信息
返回typeof(T).GetMethod(methodName);
}
公共呼叫者()
{
MethodInfo method=GetMethod(m=>nameof(m.赞助商));
}
}

注意:当有多个使用相同名称的方法重载时,这将不起作用。

我希望
q.shandor
能起作用-您在尝试时看到了什么问题?(考虑到
对象
不满足约束条件,您在
q.赞助商
中遇到的错误是完全可以理解的。)“'BaseIdea'必须是带有公共无参数构造函数的非抽象类型,才能用作参数't'”它是抽象的(并且必须是)您的泛型类型约束是
t:BaseIdea,new()
,这意味着
T
必须是从
BaseIdea
派生的类型,该类型不是抽象的,并且具有公共无参数构造函数。通过的类型必须满足所有这些条件。我怀疑
BaseIdea
本身是抽象的,或者它没有公共的无参数构造函数。这很简单,当您编写调用泛型方法的代码时,必须传递满足所有泛型类型约束的类型。Thx。我没有提供“BaseIdea”是抽象的信息。对不起。我添加了另一个派生自“BaseIdea”的类,并将其用作泛型类型参数谢谢您的回答。我自由地修改它以匹配我的问题。(这是我的错,问题中缺少了“摘要”,而不是你的。但是其他可能在这里结束的人应该得到我问题的正确答案)
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));
    }
}