Получение RuntimeMethodInfo из универсальных перегруженных методов в нестандартном статическом классе

#c# #system.reflection #methodinfo

#c# #system.reflection #methodinfo

Вопрос:

Я пытаюсь получить информацию о методе времени выполнения в статическом классе. У меня есть четыре статических метода внутри класса, и каждое имя равно, также имя параметра равно. Единственное различие заключается в их типах. Один из четырех методов имеет строковый параметр, поэтому легко получить информацию о методе. Однако другие не работают. Я нахожу несколько советов, но они не работают.

Весь тестовый код здесь.

 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
        amp;amp; p.Parameters[0].ParameterType.IsGenericType
        amp;amp; 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;
    }
}
 

Комментарии:

1. «не работает» означает, что именно?

2. Возвращает значение null. Они работают, когда только один общий с тем же именем или другим количеством параметров и т. Д. В моем сценарии я всегда получаю null. В коде строка res является примером из stackoverflow. Также он возвращает значение null

3. Извините, что вы ожидаете, что он вернет? Он вернет первый TestMethod , для которого существует именно общий параметр on, который имеет общее определение ICollection<> . У вас нет такого метода.

4. ОК. Что такое Dictionary<,>? Как я получаю информацию о каждом методе? Очевидно, что я не могу получить информацию о методе, кроме как с помощью строкового параметра. Итак, я пытаюсь понять, почему? И каково решение?

Ответ №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) });
 

Здесь есть интересное чтение по этой теме.

Комментарии:

1. Примечание: я использую .NET 5, и метод GetRuntimeMethod работает и находит ожидаемые методы.

Ответ №2:

Допустим, мы хотели бы использовать этот метод для получения any MethodInfo для различных TestMethod . Обратите внимание, что все они имеют ровно один параметр, поэтому p.Parameters.Length == 1 бесполезны:

  1. Определяется как bool TestMethod(string item) . Мы можем использовать
     .FirstOrDefault(p => p.Method.IsGenericMethod)
 
  1. Определяется как bool TestMethod<TKey, TValue>(Dictionary<TKey, TValue> item)
     .FirstOrDefault(p =>
        p.Method.IsGenericMethod amp;amp;
        p.Method.GetGenericArguments().Length == 2)
 
  1. Определяется как bool TestMethod<T>(T item)
     .FirstOrDefault(p =>
        p.Method.IsGenericMethod amp;amp;
        p.Parameters[0].ParameterType == m.Method.GetGenericArguments()[0]
        )
 
  1. Определяется как TestMethod<T>(List<T> item)
     .FirstOrDefault(p =>
        p.Method.IsGenericMethod amp;amp;
        p.Parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(List<>)
        )
 

Ответ №3:

В случае generic методов вам необходимо запросить MethodInfo объект, чтобы получить соответствующий метод.

Вы можете сделать это, как показано ниже —

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

В вашем случае получение MethodInfo for TestMethod<T> немного сложно, но ниже должно работать —

 var genericMethodInfo = typeof(TestClass).GetMethods().Single(m => m.Name == "TestMethod" amp;amp; m.IsGenericMethod amp;amp;
!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" amp;amp; m.IsGenericMethod amp;amp;
m.GetGenericMethodDefinition().GetParameters()[0].ParameterType.IsGenericType amp;amp; 
m.GetGenericMethodDefinition().GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(Dictionary<,>));

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

var listMethodInfo = typeof(TestClass).GetMethods().Single(m => m.Name == "TestMethod" amp;amp; m.IsGenericMethod amp;amp;
m.GetGenericMethodDefinition().GetParameters()[0].ParameterType.IsGenericType amp;amp; 
m.GetGenericMethodDefinition().GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(List<>));