繁体   English   中英

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

[英]Calling generic method with constraints using 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>替换它,但这也不起作用

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

到目前为止,这应该可以工作:

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM