.net 如何为接受泛型参数的泛型函数调用GetMethod(不使用GetMethods)?

zpqajqem  于 2023-05-30  发布在  .NET
关注(0)|答案(4)|浏览(418)

我知道我可以使用GetMethods获取方法信息,但我想知道如何在没有GetMethods的情况下正确地执行此操作。我读过其他的SO问题和答案,建议这是不可能的,或者建议使用LINQ代替,但这并不是问题的答案。
在最基本的层次上考虑一个静态泛型函数,它接受一个泛型参数。

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

要获取这个方法信息,我们可以调用Type.GetMethod("Test", BindingFlags.Static | BindingFlags.NonPublic)。但是,如果由于某种原因我们不能使用这个简单的GetMethod签名(可能是由于多个重载),那么我们需要提供参数类型。问题是我无法创建一个与T val参数精确匹配的参数类型。有趣的是,我可以从方法info(用GetMethods获取)中获取参数,并将其传递给GetMethod以获得所需的结果。这意味着如果只能创建适当的泛型类型(将IsGenericParameter设置为true),那么我觉得这是完全可能的。
这意味着这在.NET中是完全可能的,只需要创建适当的类型示例。如何创建这些类型示例?如果它们不可能被创造出来,为什么不呢?
我创建了a simple fiddle来展示这个问题。

ttvkxqim

ttvkxqim1#

它不是现成的,因为你需要的类型实际上是泛型类型参数,只存在于方法/参数定义中。例如,在您的Test<T>(T val)中,参数类型是“由Test<T>定义的T”。你不能构建它,因为它不是由任何东西组成的。获得T的唯一方法是通过GetParameters()
基本上,这意味着:《The Hard Way》(英语:The Hard Way)例如:

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);
svdrlsy4

svdrlsy42#

这不是调用GetMethod,而是获取泛型方法定义的“另一种”方法是将方法组“强制转换”为特定类型,然后在其上调用.Method.GetGenericDefinition()
在您的示例中,您需要的方法签名是Action<object>,其中object只是一个占位符,可以是与泛型方法的约束相匹配的任何类型。

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

您可以使用以下命令选择一个不同的“Test”重载,将其定义为private static T Test<T>(T val, int counter)

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

c0vxltue3#

我觉得这不可能。但其他方法(仍然很难,我相信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完全相同的结果。

ztmd8pv5

ztmd8pv54#

有点晚了,但为了将来的参考,以下内容也适用于.NET核心

var flags = BindingFlags.Static | BindingFlags.NonPublic;
//the 0 indicates the index of the parameter
var paramTypes1 = new[] { Type.MakeGenericMethodParameter(0) };

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

或者只是

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

假设方法签名为

Test<T>(string val)

然后paramTypes1变为

var paramTypes1 = new[] {typeof(string), Type.MakeGenericMethodParameter(0) };

即使泛型不是一个参数,也需要在数组中提到它

相关问题