Вы можете несколько элегантно выбрать конкретную универсальную перегрузку метода во время компиляции, не передавая строки для поиска во время выполнения, как это делают другие ответы.
Статические методы
Предположим, у вас есть несколько статических методов с одним именем, например:
public static void DoSomething<TModel>(TModel model)
public static void DoSomething<TViewModel, TModel>(TViewModel viewModel, TModel model)
// etc
Если вы создаете Action или Func, который соответствует общему количеству и количеству параметров искомой перегрузки, вы можете выбрать его во время компиляции с относительно небольшим количеством акробатики.
Пример: выберите первый метод - возвращает void, поэтому используйте Action, требуется один универсальный. Мы используем объект, чтобы пока не указывать тип:
var method = new Action<object>(MyClass.DoSomething<object>);
Пример: выберите второй метод - возвращает void, поэтому Action, 2 универсальных типа, поэтому используйте тип объекта дважды, один раз для каждого из 2 универсальных параметров:
var method = new Action<object, object>(MyClass.DoSomething<object, object>);
Вы только что получили метод, который вам нужен, без каких-либо сумасшедших действий по сантехнике и без поиска во время выполнения или использования рискованных строк.
MethodInfo
Обычно в Reflection вам нужен объект MethodInfo, который вы также можете получить безопасным для компиляции способом. Это когда вы передаете фактические универсальные типы, которые вы хотите использовать в своем методе. Предполагая, что вы хотели второй метод выше:
var methodInfo = method.Method.MakeGenericMethod(type1, type2);
Это ваш универсальный метод, без поиска отражений, вызовов GetMethod () или хлипких строк.
Методы статического расширения
Конкретный пример, который вы приводите в Queryable. Перегрузки где заставляют вас немного задуматься в определении Func, но, как правило, следуют той же схеме. Подпись для наиболее часто используемого метода расширения Where () :
public static IQueryable<TModel> Where<TModel>(this IQueryable<TModel>, Expression<Func<TModel, bool>>)
Очевидно, что это будет немного сложнее - вот оно:
var method = new Func<IQueryable<object>,
Expression<Func<object, bool>>,
IQueryable<object>>(Queryable.Where<object>);
var methodInfo = method.Method.MakeGenericMethod(modelType);
Методы экземпляра
Включение комментария Валери - чтобы получить метод экземпляра, вам нужно сделать что-то очень похожее. Предположим, у вас есть этот метод экземпляра в вашем классе:
public void MyMethod<T1>(T1 thing)
Сначала выберите метод так же, как для статики:
var method = new Action<object>(MyMethod<object>);
Затем вызовите GetGenericMethodDefinition()
, чтобы перейти к универсальному MethodInfo, и, наконец, передайте ваш тип (ы) с помощью MakeGenericMethod()
:
var methodInfo = method.Method.GetGenericMethodDefinition().MakeGenericMethod(type1);
Разделение MethodInfo и типов параметров
Это не было запрошено в вопросе, но как только вы сделаете вышеописанное, вы можете выбрать метод в одном месте и решить, какие типы передать в другом. Вы можете отделить эти 2 шага.
Если вы не уверены в параметрах универсального типа, которые собираетесь передать, вы всегда можете получить объект MethodInfo без них.
Статический:
var methodInfo = method.Method;
Instance:
var methodInfo = method.Method.GetGenericMethodDefinition();
И передать это другому методу, который знает типы, которые он хочет создать, и вызвать метод с помощью - например:
processCollection(methodInfo, type2);
...
protected void processCollection(MethodInfo method, Type type2)
{
var type1 = typeof(MyDataClass);
object output = method.MakeGenericMethod(type1, type2).Invoke(null, new object[] { collection });
}
Одна вещь, с которой это особенно помогает, - это выбор конкретного метода экземпляра класса изнутри класса, а затем предоставление его внешним вызывающим, которые впоследствии нуждаются в нем с различными типами.
Правки: Исправлены объяснения, включен пример метода экземпляра Валери.