Frage

Ich versuche, eine Expression zu erstellen, die eine bestimmte generisch überladene Methode (Enumerable.Average in meinem ersten Testfall) aufruft. Die spezifische Typ Bindungen werden erst zur Laufzeit jedoch bekannt, so dass ich Reflection verwenden muß, finden und erstellen die richtige generische Methode (die Expression aus analysiert Text erstellt werden).

Also, wenn ich weiß, zur Laufzeit, dass ich diese spezifische Überlastung finden will:

public static double Average<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)

Wie löse ich diese bestimmte MethodInfo Reflexion mit?

Bisher habe ich die folgende Auswahlanweisung:

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();
}

Die es oben verengt zu drei Überlastungen nach unten, aber ich möchte reflektieren und die spezifische Überlastung zu finden, die eine Func<TSource, int> nimmt wo argType == typeof(int).

Ich bin ratlos und jede Hilfe ist willkommen.

War es hilfreich?

Lösung

Sie müssen verwenden MethodInfo.MakeGenericMethod

EDIT: OK, ich habe das Problem falsch verstanden hatte ... Diese Methode sollte das tun, was Sie wollen:

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();
}

Andere Tipps

Da Sie einen Ausdruck Gebäude sind nicht direkt ausgeführt wird, können Sie den Schritt Method überspringen und direkt auf die Method die Expression.Call Überlastung verwenden, die einen Methodennamen nimmt eher als ein Method.

var call = Expression.Call(typeof(Enumerable),
             "Average",
            new Type[] { typeof(MyTSource) },
            enumerableParameter, lambdaParameter
                );

Hier ist, wie es zu tun:

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();
}

Danke @Joren für den verknüpften Hinweis. Das Beispiel differenziert auf Argument Zählung basiert, aber es hat mich in der richtigen Richtung.

Die Auswahl, die funktioniert, ist

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;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top