Domanda

Sto tentando di creare un Expression che invocare una specifica generica metodo di overload (Enumerable.Average nel mio primo banco di prova). Gli attacchi di tipo specifico non sono noti fino al runtime tuttavia quindi ho bisogno di usare Reflection per trovare e creare il metodo generico corretta (la Expression viene creato dal testo analizzato).

Quindi, se io so in fase di esecuzione che voglio trovare questo sovraccarico specifica:

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

Come posso risolvere quel particolare MethodInfo utilizzando la riflessione?

Finora ho la seguente dichiarazione selezione:

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

È possibile che questo restringe il campo a tre sovraccarichi ma voglio riflettere e trovare il sovraccarico di specifico che prende un Func<TSource, int> dove argType == typeof(int).

Sono perplesso e ogni aiuto è apprezzato.

È stato utile?

Soluzione

È necessario utilizzare MethodInfo.MakeGenericMethod

EDIT: OK, avevo frainteso il problema ... Questo metodo dovrebbe fare quello che vuoi:

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

Altri suggerimenti

Dal momento che si sta costruendo un'espressione piuttosto che eseguire direttamente, è possibile ignorare il passaggio MethodInfo e andare direttamente al MethodCallExpression utilizzando il sovraccarico Expression.Call che prende nome di un metodo piuttosto che un MethodInfo.

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

Ecco come si fa:

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

Grazie per il suggerimento @Joren collegato. Questo esempio differenzia basa sul conteggio argomento per, ma mi ha fatto nella giusta direzione.

La scelta che funziona è

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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top