كيف يمكنني العثور على التحميل الزائد عام محدد باستخدام التفكير؟
-
13-09-2019 - |
سؤال
أنا أحاول إنشاء Expression
من شأنها أن تستدعي طريقة محددة عامة محددة (Enumerable.Average
في حالة الاختبار الأولى). لا تعرف ارتباطات النوع المحددة حتى وقت التشغيل، لذلك أحتاج إلى استخدام Reflection
لإيجاد وإنشاء الطريقة العامة الصحيحة ( Expression
يتم إنشاؤها من نص التحليل).
لذلك إذا كنت أعرف في وقت التشغيل الذي أريد العثور على هذا التحميل الزائد المحدد:
public static double Average<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)
كيف يمكنني حل هذا بشكل خاص MethodInfo
باستخدام الانعكاس؟
حتى الآن لدي بيان الاختيار التالي:
MethodInfo GetMethod(Type argType, Type returnType)
{
var methods = from method in typeof(Enumerable).GetMethods(BindingFlags.Public | BindingFlags.Static)
where method.Name == "Average" &&
method.ContainsGenericParameters &&
method.GetParameters().Length == 2 &&
// and some condition where method.GetParameters()[1] is a Func that returns type argType
method.ReturnType == returnType
select method;
Debug.Assert(methods.Count() == 1);
return methods.FirstOrDefault();
}
ما سبق يضيقه إلى ثلاثة حمالات زائدة ولكن أريد أن أعكس وإيجاد التحميل الزائد المحدد الذي يأخذ Func<TSource, int>
أين argType == typeof(int)
.
أنا جذري وأي مساعدة موضع تقدير.
المحلول
تحتاج إلى استخدام methodInfo.makegenericmethod.
تحرير: حسنا، لقد أسيء فهم المشكلة ... يجب أن تفعل هذه الطريقة ما تريد:
MethodInfo GetMethod(Type argType, Type returnType)
{
var enumerableType = typeof(IEnumerable<>).MakeGenericType(new Type[] { argType });
Console.WriteLine(enumerableType);
var methods = from method in typeof(Enumerable).GetMethods(BindingFlags.Public | BindingFlags.Static)
let parameters = method.GetParameters()
let genParams = method.GetGenericArguments()
where method.Name == "Average" &&
method.ContainsGenericParameters &&
parameters.Length == 2 &&
parameters[1].ParameterType.GetGenericTypeDefinition() == typeof(Func<,>) &&
parameters[1].ParameterType.GetGenericArguments()[1] == argType &&
method.ReturnType == returnType
select method;
return methods.FirstOrDefault();
}
نصائح أخرى
نظرا لأنك تقوم ببناء تعبير بدلا من التنفيذ مباشرة، فيمكنك تخطي الخطوة المنهة
var call = Expression.Call(typeof(Enumerable),
"Average",
new Type[] { typeof(MyTSource) },
enumerableParameter, lambdaParameter
);
هيريس كيفية القيام بذلك:
static MethodInfo GetMethod(Type argType, Type returnType)
{
var methods = from m in typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
where m.ContainsGenericParameters
&& m.Name == "Average"
&& m.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Func<,>)
&& m.GetParameters()[1].ParameterType.GetGenericArguments()[1] == returnType
select m;
return methods.First();
}
شكرا joren للتلميح المرتبط. يميز هذا المثال بناء على الحجة، لكنه حصلت لي في الاتجاه الصحيح.
التحديد الذي يعمل هو
var methods = from method in typeof(Enumerable).GetMethods(BindingFlags.Public | BindingFlags.Static)
where method.Name == Name &&
method.ContainsGenericParameters &&
method.ReturnType == returnType &&
method.GetParameters().Length == 2 &&
method.GetParameters()[1].ParameterType.GetGenericArguments().Count() == 2 &&
method.GetParameters()[1].ParameterType.GetGenericArguments()[1] == argType
select method;