使用反射调用具有约束的通用方法

时间:2019-02-19 13:11:38

标签: c# generics reflection constraints

我使用Reflection从通用方法中检索methodInfo:

public void Sponsor<T>(int id)  where T : BaseIdea, new() {
  // Do something
}

这很好。但是,如果该方法具有以下约束:

q.Sponsor<object>

q.Sponsor<BaseIdea>(在调用方内部)无法编译:

  

类型“对象”不能用作泛型中的类型参数“ T”   类型或方法'ModuleBaseLogic.Sponsor(int)'没有隐式   从“对象”到“ BaseIdea”的引用转换。

我尝试用.env替换它,但这也不起作用

3 个答案:

答案 0 :(得分:2)

这里有一些例子,如果您有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.
}

答案 1 :(得分:2)

目前应该可以使用:

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)一样,对于具有任何通用约束的任何方法,object都不可以是通用参数。 BaseIdea不能是通用参数,因为它是抽象参数,这对于基类通常是必需的。 最简单的参数是一个具体类,它是从BaseIdea派生的,它由我的ConcreteIdea-class给出。 正如kara所提到的,new()约束还需要一个无参数的构造函数,该构造函数也可以是隐式构造函数(默认构造函数)。

答案 2 :(得分:2)

另一种方法是使用一个表达式,该表达式通过使用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));
    }
}

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