Ссылка на требуемый перегруженный общий метод
данный
public Class Example
{
public static void Foo< T>(int ID){}
public static void Foo< T,U>(int ID){}
}
Вопросы:
- Правильно ли это назвать "перегруженным общим методом"?
-
Как можно указать какой-либо метод при создании объекта MethodInfo?
Type exampleType = Type.GetType("fullyqualifiednameOfExample, namespaceOfExample");
MethodInfo mi = exampleType.GetMethod("Foo", BindingFlags.Public|BindingFlags.Static, null, new Type[] {typeof(Type), typeof(Type) }, null);
аргумент 4 приводит к большому недовольству компилятора
Ответы
Ответ 1
Я не могу найти способ использования GetMethod, который будет делать то, что вы хотите. Но вы можете получить все методы и пройти список, пока не найдете нужный метод.
Помните, что вам нужно вызвать MakeGenericMethod, прежде чем вы сможете его использовать.
var allMethods = typeof (Example).GetMethods(BindingFlags.Public | BindingFlags.Static);
MethodInfo foundMi = allMethods.FirstOrDefault(
mi => mi.Name == "Foo" && mi.GetGenericArguments().Count() == 2);
if (foundMi != null)
{
MethodInfo closedMi = foundMi.MakeGenericMethod(new Type[] {typeof (int), typeof (string)});
Example example= new Example();
closedMi.Invoke(example, new object[] { 5 });
}
Ответ 2
Вот ответы на ваши вопросы вместе с примером:
-
Да, хотя есть две вещи, которые нужно знать здесь с помощью общих методов, введите метод вывода вывода и метода перегрузки. Вывод типа происходит во время компиляции, прежде чем компилятор попытается разрешить перегруженные сигнатуры методов. Компилятор применяет логику вывода типа ко всем универсальным методам, которые имеют одно и то же имя. На этапе разрешения перегрузки компилятор включает только те общие методы, для которых тип вывода преуспел. Подробнее здесь
-
См. полный пример кода программы приложения Console, который показывает, как несколько вариантов метода Foo могут быть указаны при создании объекта MethodInfo, а затем вызывается с использованием метода расширения:
Program.cs
class Program
{
static void Main(string[] args)
{
MethodInfo foo1 = typeof(Example).GetGenericMethod("Foo",
new[] { typeof(string) },
new[] { typeof(int) },
typeof(void));
MethodInfo foo2 = typeof(Example).GetGenericMethod("Foo",
new[] { typeof(string), typeof(int) },
new[] { typeof(int) },
typeof(void));
MethodInfo foo3 = typeof(Example).GetGenericMethod("Foo",
new[] { typeof(string) },
new[] { typeof(string) },
typeof(void));
MethodInfo foo4 = typeof(Example).GetGenericMethod("Foo",
new[] { typeof(string), typeof(int) },
new[] { typeof(int), typeof(string) },
typeof(string));
Console.WriteLine(foo1.Invoke(null, new object[] { 1 }));
Console.WriteLine(foo2.Invoke(null, new object[] { 1 }));
Console.WriteLine(foo3.Invoke(null, new object[] { "s" }));
Console.WriteLine(foo4.Invoke(null, new object[] { 1, "s" }));
}
}
Example.cs:
public class Example
{
public static void Foo<T>(int ID) { }
public static void Foo<T, U>(int ID) { }
public static void Foo<T>(string ID) { }
public static string Foo<T, U>(int intID, string ID) { return ID; }
}
Extensions.cs:
public static class Extensions
{
public static MethodInfo GetGenericMethod(this Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType)
{
MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static)
where m.Name == name &&
m.GetGenericArguments().Length == genericArgTypes.Length &&
m.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(argTypes) &&
m.ReturnType == returnType
select m).Single().MakeGenericMethod(genericArgTypes);
return foo1;
}
}
Ответ 3
Вот однострочный Linq для того, что вам нужно:
MethodInfo mi = exampleType.GetMethods().First(m=>m.GetGenericArguments().Length == 2);
Ответ 4
лучше:
Пример попытается получить правильную перегрузку System.Linq.Enumerable.Select
private static MethodInfo GetMethod<T>(Expression<Func<T>> expression)
{
return ((MethodCallExpression)expression.Body).Method;
}
public static void CallSelect()
{
MethodInfo definition = GetMethod(() => Enumerable.Select(null, (Func<object, object>)null)).GetGenericMethodDefinition();
definition.MakeGenericMethod(typeof(int), typeof(int)).Invoke(null, new object[] { new List<int>(), ((Func<int, int>)(x => x)) });
}
Ответ 5
Я делаю небольшую модификацию вашего лямбда-запроса.
Когда тип параметра si generic вы должны сделать так:
Я добавляю pi.ParameterType.GetGenericTypeDefinition()
и
(m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType)
Таким образом, метод работает очень хорошо
MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static)
where m.Name == name
&& m.GetGenericArguments().Length == genericArgTypes.Length
&& m.GetParameters().Select(pi => pi.ParameterType.IsGenericType ? pi.ParameterType.GetGenericTypeDefinition() : pi.ParameterType).SequenceEqual(argTypes) &&
(returnType==null || (m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType)
select m).FirstOrDefault();
if (foo1 != null)
{
return foo1.MakeGenericMethod(genericArgTypes);
}
return null;
Пример:
С изменением метода, который я могу вызвать
этот метод расширения
public static IQueryable<T> FilterCulture<T>(this Table<T> t, IDatabaseFilter filter)
С моим новым Помощником вроде этого
var QueryableExpression = MethodInfoHelper.GetGenericMethod(typeof(LinqFilterExtension), "FilterCulture", new Type[] { rowType }, new Type[] { typeof(Table<>), typeof(IDatabaseFilter) }, typeof(IQueryable<>));
Подпись моего помощника
public static MethodInfo GetGenericMethod(Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType)