Get RuntimeMethodInfo from generic overloaded methods in non-generic static class

651 Views Asked by At

I try to get runtime method infoes in static class. I have four static method inside the class and each name is equal, also parameter name is equal. The only difference is their types. One of four method has string parameter so it is easy to get method info. However the others don't working. I find several advice but that are not working.

All test code is here.

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;
    }
}
3

There are 3 best solutions below

1
steve16351 On BEST ANSWER

If you are using .net core 2.1 or greater, you can use Type.MakeGenericMethodParameter to let you refer to a generic parameter of a method. You can use that to create a generic type argument that will work with GetMethod (not available for 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) });

Some interesting reading on the topic here.

0
Charlieface On

Let's say we would like to use this method to get any MethodInfo for the various TestMethod. Note that they all have exactly one parameter, so p.Parameters.Length == 1 is useless:

  1. Defined as bool TestMethod(string item). We can use
    .FirstOrDefault(p => p.Method.IsGenericMethod)
  1. Defined as bool TestMethod<TKey, TValue>(Dictionary<TKey, TValue> item)
    .FirstOrDefault(p =>
        p.Method.IsGenericMethod &&
        p.Method.GetGenericArguments().Length == 2)
  1. Defined as bool TestMethod<T>(T item)
    .FirstOrDefault(p =>
        p.Method.IsGenericMethod &&
        p.Parameters[0].ParameterType == m.Method.GetGenericArguments()[0]
        )
  1. Defined as TestMethod<T>(List<T> item)
    .FirstOrDefault(p =>
        p.Method.IsGenericMethod &&
        p.Parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(List<>)
        )
0
Nikhil Patil On

In case of generic methods you have to query the MethodInfo object to get the appropriate method.

You can do it as below -

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

In your case, getting the MethodInfo for TestMethod<T> is bit tricky, but below should work -

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

Final Code -

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