如何调用GetMethod获取带有泛型参数的泛型函数(不使用GetMethods)?

时间:2015-04-27 19:15:10

标签: c# .net generics reflection

我知道我可以使用GetMethods获取方法信息,但我想知道如何在没有GetMethods的情况下正确执行此操作。我已经阅读了其他SO问题和答案,表明这是不可能的,或建议只使用LINQ,但这不是问题的答案。

从最基本的层面考虑一个静态泛型函数,它接受一个通用参数。

private static void Test<T>(T val)
{
}

要获取此方法信息,我们只需拨打Type.GetMethod("Test", BindingFlags.Static | BindingFlags.NonPublic)即可。但是如果有一些原因我们无法使用这个简单的GetMethod签名(可能是由于多次重载),那么我们需要提供参数类型。问题是我无法创建与T val参数精确匹配的参数类型。有趣的是,我可以从方法信息中获取参数(使用GetMethods获取)并将其传递到GetMethod以获得所需的结果。这意味着如果只能创建适当的泛型类型(IsGenericParameter设置为true),那么我觉得这是完全可能的。

这意味着这在.NET中是完全可能的,并且只需要创建正确的类型实例。如何创建这些类型实例?如果他们不可能创造,为什么他们不是?

我创建了a simple fiddle来展示问题。

3 个答案:

答案 0 :(得分:5)

它不容易获得,因为您需要的类型实际上是方法/参数定义中仅存在的泛型类型参数。例如,在Test<T>(T val)中,参数类型为&#34; TTest<T>定义。您无法构建,因为它不是组成的任何东西。获取T的唯一方法是通过GetParameters()

基本上,它留下了:艰难的方式 - 即手动。例如:

var method1 = typeof(Program).GetMethods(flags).Single(x => x.Name == "Test"
     && x.IsGenericMethodDefinition && x.GetParameters().Length == 1
      && x.GetParameters()[0].ParameterType == x.GetGenericArguments()[0])
    .MakeGenericMethod(paramTypes1);

如果您知道只有一种Test(...)方法,显然会更简单:

var method = typeof(Program).GetMethod("Test", flags)
    .MakeGenericMethod(paramTypes1);

答案 1 :(得分:2)

这不是调用GetMethod而是&#34;其他&#34;获得通用方法定义的方法是&#34; cast&#34;方法组到特定类型,然后在其上调用.Method.GetGenericDefinition()

在您的示例中,您需要的方法签名是Action<object>,其中object只是一个占位符,可以是与泛型方法的约束匹配的任何类型。

var genericMethodDefinition =
    ((Action<object>)Test<object>).Method.GetGenericMethodDefinition();

你可以选择不同的重载&#34;测试&#34;通过使用以下内容定义为private static T Test<T>(T val, int counter)

var genericMethodDefinition2 =
    ((Func<object, int, object>)Test<object>).Method.GetGenericMethodDefinition();

答案 2 :(得分:1)

好吧,我不认为这是可能的。 但其他方法(仍然很难,我相信GetMethods会更好):

var method1 =
    typeof (Program).GetMember("Test*",
                               BindingFlags.InvokeMethod |
                               BindingFlags.NonPublic | 
                               BindingFlags.Static)
                    .Cast<MethodInfo>()
                    .Single(
                            m =>
                            m.GetGenericArguments().Length == 1 &&
                            m.GetGenericArguments()[0].IsGenericParameter)
                    .MakeGenericMethod(paramTypes1);

当然,您可以省略MakeGenericMethod以获得与method2相同的结果。