Question

Je cherche à créer un Expression qui invoquer une méthode surchargée générique spécifique (Enumerable.Average dans mon premier test). Les liaisons de type spécifique ne sont pas connus jusqu'à ce que l'exécution mais si je dois utiliser Reflection pour trouver et créer la méthode générique correcte (la Expression est créée à partir du texte analysé).

Donc, si je sais à l'exécution que je veux trouver cette surcharge spécifique:

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

Comment puis-je résoudre ce MethodInfo particulier en utilisant la réflexion?

Jusqu'à présent, je compte de la sélection suivante:

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

Le rétrécissant au-dessus jusqu'à trois, mais je veux les surcharges à réfléchir et à trouver la surcharge spécifique qui prend un Func<TSource, int>argType == typeof(int).

Je suis perplexe et toute aide est appréciée.

Était-ce utile?

La solution

Vous devez utiliser MethodInfo.MakeGenericMethod

EDIT: OK, j'avais mal compris le problème ... Cette méthode devrait faire ce que vous voulez:

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

Autres conseils

Puisque vous construisez une expression plutôt que d'exécuter directement, vous pouvez sauter l'étape MethodInfo et aller directement à la MethodCallExpression en utilisant la surcharge de Expression.Call qui prend un nom de méthode plutôt qu'une MethodInfo.

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

Voici comment faire:

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

Merci pour l'astuce @Joren liée. Cet exemple différencie en fonction du nombre d'arguments pour, mais il m'a dans la bonne direction.

La sélection qui fonctionne est

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;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top