#c# #generics #reflection
#c# #универсальные методы #отражение
Вопрос:
Я пытаюсь вызвать универсальный метод во время выполнения и получить рабочий код. Однако мне было интересно, есть ли лучший способ получения информации о методе, так как если я изменю имя метода, это сломается.
public int Handle<T>(CreateCodeModel obj) where T : CodeModel
{
//Create code here...
}
//codeType is selected by user.
public int Handle(CreateCodeModel obj, Type codeType)
{
MethodInfo method = this.GetType().GetMethod("Handle");
//MethodInfo method = this.GetType().GetMethods()
.Where(mi => mi.IsGenericMethod amp;amp; mi.Name == "Handle").First();
MethodInfo genericMethod = method.MakeGenericMethod(new Type[] { codeType });
return (int)genericMethod.Invoke(this, new object[] { obj });
}
Я надеялся, что есть более удобный способ сделать это, возможно, используя действия для получения информации о методе, но тогда мне все равно нужно указать тип, например
Action<CreateCodeModel> h = (x) => Handle(x);
MethodInfo method = h.Method;
Комментарии:
1. По крайней мере, вы могли бы использовать
nameof
, а не жестко закодированную строку. Таким образом, если метод переименован, вы получите ошибку компилятора, предполагающую, что такие инструменты, как R # или ваша IDE, не применяют рефакторинг для вас.2. Спасибо, сделаю. Но там, где у меня есть перегруженные методы, это не вызовет ошибок компилятора, если я не переименую оба метода. Поэтому я надеялся, что есть способ использовать действие или выражение. Но, возможно, это невозможно, или я использую неправильный подход…
Ответ №1:
Здесь вы на правильном пути. Подпись вашего делегата должна соответствовать вызываемому вами методу, поэтому в данном случае это было бы Func<CreateCodeModel,int>
вместо Action<CreateCodeModel>
. И вы должны указать общий параметр, который соответствует общим ограничениям. Это может быть что угодно, поскольку мы просто удалим его с помощью нашего вызова GETGENERICMETHOD Definition , но мне нравится использовать класс из ограничения.
Другой фрагмент кода ниже — это идея о том, что вам нужно получить определение универсального метода только один раз, поскольку оно не меняется, поэтому я сохраняю его в статической переменной, чтобы его можно было использовать повторно.
public int Handle<T>(CreateCodeModel obj) where T : CodeModel
{
//Create code here...
return 7;
}
// this static variable preserves the generic MethodInfo, so we don't have
// keep discovering it with reflection
private static MethodInfo _methodInfoForHandle;
// The generic MethodInfo only needs to be discovered the first time this runs
private MethodInfo MethodInfoForHandle
{
get
{
return _methodInfoForHandle ?? (_methodInfoForHandle = GetMethodInfoForHandleMethod());
}
}
private MethodInfo GetMethodInfoForHandleMethod()
{
Func<CreateCodeModel, int> handleFunc = Handle<CodeModel>;
return handleFunc.Method.GetGenericMethodDefinition();
}
//codeType is selected by user.
public int Handle(CreateCodeModel obj, Type codeType)
{
MethodInfo genericMethod = MethodInfoForHandle.MakeGenericMethod(new Type[] { codeType });
return (int)genericMethod.Invoke(this, new object[] { obj });
}
public class CreateCodeModel { }
public class CodeModel { }
public class JavascriptCodeModel : CodeModel { }