【问题标题】:Get RuntimeMethodInfo from generic overloaded methods in non-generic static class从非泛型静态类中的泛型重载方法中获取 RuntimeMethodInfo
【发布时间】:2021-01-24 13:22:12
【问题描述】:

我尝试在静态类中获取运行时方法信息。我在类中有四个静态方法,每个名称都相等,参数名称也相等。唯一的区别是它们的类型。四种方法之一具有字符串参数,因此很容易获取方法信息。然而其他人不工作。我找到了一些建议,但都不起作用。

所有测试代码都在这里。

class Program {
    static void Main(string[] args) {
        //ok
        var stringMethodInfo = typeof(TestClass).GetRuntimeMethod("TestMethod", new[] { typeof(string) });
        //not working
        var dictMethodInfo = typeof(TestClass).GetRuntimeMethod("TestMethod", new[] { typeof(Dictionary<,>) });
        //not working
        var genericMethodInfo = typeof(TestClass).GetRuntimeMethod("TestMethod", new[] { typeof(object) });
        //not working
        var listMethodInfo = typeof(TestClass).GetRuntimeMethod("TestMethod", new[] { typeof(List<>) });


        //not working
        var res = typeof(TestClass)
        .GetRuntimeMethods()
        .Where(x => x.Name.Equals("TestMethod"))
        .Select(m => new { Method = m, Parameters = m.GetParameters() })
        .FirstOrDefault(p =>
            p.Parameters.Length == 1
        && p.Parameters[0].ParameterType.IsGenericType
        && p.Parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(ICollection<>)
        );

    }
}


public static class TestClass {
    public static bool TestMethod(string item) {
        return true;
    }

    public static bool TestMethod<TKey, TValue>(Dictionary<TKey, TValue> item) {
        return true;
    }

    public static bool TestMethod<T>(T item) {
        return true;
    }

    public static bool TestMethod<T>(List<T> item) {
        return true;
    }
}

【问题讨论】:

  • “不工作”到底是什么意思?
  • 返回空值。当只有一个具有相同名称或不同数量的参数等的泛型时,它们正在工作。在我的场景中,我总是得到空值。在代码中, res 行是 stackoverflow 的一个示例。它也是返回 null
  • 抱歉,您希望它返回什么?它将返回第一个TestMethod,其中恰好有通用参数,其通用定义为ICollection&lt;&gt;。你没有这种方法。
  • 好的。什么是字典?我如何获得每个方法信息?显然,除了字符串参数外,我无法获取方法信息。所以我试着理解为什么?解决方案是什么?

标签: c# system.reflection methodinfo


【解决方案1】:

如果您使用.net core 2.1 或更高版本,您可以使用Type.MakeGenericMethodParameter 让您引用方法的泛型参数。您可以使用它来创建适用于GetMethod 的泛型类型参数(不适用于GetRuntimeMethod)。

var stringMethodInfo = typeof(TestClass).GetRuntimeMethod("TestMethod", new[] { typeof(string) });
Type[] dictionaryTypeParameters = { typeof(Dictionary<,>).MakeGenericType(Type.MakeGenericMethodParameter(0), Type.MakeGenericMethodParameter(1)) };
MethodInfo dictMethodInfo = typeof(TestClass).GetMethod("TestMethod", 2, dictionaryTypeParameters);
MethodInfo listMethodInfo = typeof(TestClass).GetMethod("TestMethod", 1, new[] { typeof(List<>).MakeGenericType(Type.MakeGenericMethodParameter(0)) });
MethodInfo genericMethodInfo = typeof(TestClass).GetMethod("TestMethod", 1, new[] { Type.MakeGenericMethodParameter(0) });

关于主题here的一些有趣的阅读。

【讨论】:

  • 注意:我使用 .NET 5 并且 GetRuntimeMethod 有效并找到了预期的方法。
【解决方案2】:

假设我们想使用这种方法来获取各种TestMethod 的任何MethodInfo。注意它们都只有一个参数,所以p.Parameters.Length == 1 没用:

  1. 定义为bool TestMethod(string item)。我们可以使用
    .FirstOrDefault(p => p.Method.IsGenericMethod)
  1. 定义为bool TestMethod&lt;TKey, TValue&gt;(Dictionary&lt;TKey, TValue&gt; item)
    .FirstOrDefault(p =>
        p.Method.IsGenericMethod &&
        p.Method.GetGenericArguments().Length == 2)
  1. 定义为bool TestMethod&lt;T&gt;(T item)
    .FirstOrDefault(p =>
        p.Method.IsGenericMethod &&
        p.Parameters[0].ParameterType == m.Method.GetGenericArguments()[0]
        )
  1. 定义为TestMethod&lt;T&gt;(List&lt;T&gt; item)
    .FirstOrDefault(p =>
        p.Method.IsGenericMethod &&
        p.Parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(List<>)
        )

【讨论】:

    【解决方案3】:

    对于generic 方法,您必须查询MethodInfo 对象以获取适当的方法。

    你可以这样做 -

    var dictMethodInfo = typeof(TestClass).GetMethods().Single(m => m.Name == "TestMethod" && m.IsGenericMethod &&
    m.GetGenericMethodDefinition().GetParameters()[0].ParameterType.IsGenericType && 
    m.GetGenericMethodDefinition().GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(Dictionary<,>));
    

    在您的情况下,为TestMethod&lt;T&gt; 获取MethodInfo 有点棘手,但下面应该可以工作-

    var genericMethodInfo = typeof(TestClass).GetMethods().Single(m => m.Name == "TestMethod" && m.IsGenericMethod &&
    !m.GetGenericMethodDefinition().GetParameters()[0].ParameterType.IsGenericType);
    

    最终代码 -

    var stringMethodInfo = typeof(TestClass).GetRuntimeMethod("TestMethod", new[] { typeof(string) });
    
    var dictMethodInfo = typeof(TestClass).GetMethods().Single(m => m.Name == "TestMethod" && m.IsGenericMethod &&
    m.GetGenericMethodDefinition().GetParameters()[0].ParameterType.IsGenericType && 
    m.GetGenericMethodDefinition().GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(Dictionary<,>));
    
    var genericMethodInfo = typeof(TestClass).GetMethods().Single(m => m.Name == "TestMethod" && m.IsGenericMethod &&
    !m.GetGenericMethodDefinition().GetParameters()[0].ParameterType.IsGenericType);
    
    var listMethodInfo = typeof(TestClass).GetMethods().Single(m => m.Name == "TestMethod" && m.IsGenericMethod &&
    m.GetGenericMethodDefinition().GetParameters()[0].ParameterType.IsGenericType && 
    m.GetGenericMethodDefinition().GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(List<>));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-02-10
      • 1970-01-01
      • 2015-07-30
      • 1970-01-01
      • 2010-10-30
      • 2013-04-17
      相关资源
      最近更新 更多