2017-08-29 5 views
2

Je souhaite obtenir une définition de méthode qui accepte un paramètre Action<T> en utilisant la réflexion. J'utilise le noyau .NET 1.1. Puisque la classe a deux méthodes avec le même nom, j'essaye de vérifier le type des paramètres acceptés pour m'assurer que j'obtiens la bonne définition de méthode (et pas l'autre surcharge), mais la comparaison ne semble pas fonctionner.Comparaison du type de paramètre générique à l'aide de la réflexion

Voici un code qui montre ce problème:

using System; 
using System.Linq; 
using System.Reflection; 

class ReflectMe { 
    public void SomeMethod<T>(Action<T> action) { 
     action(default(T)); 
    } 
    public T SomeMethod<T>() { 
     return default(T); 
    } 
} 

class Program { 
    static void Main(string[] args) { 
     var reflectedMethod = typeof(ReflectMe).GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.Instance) 
      .Where(m => m.Name == "SomeMethod" && m.IsGenericMethodDefinition) 
      .Where(m => { 
       var parameters = m.GetParameters(); 
       if (parameters.Count() != 1) { 
        // this filters out the 1st method 
        return false; 
       } 
       var actionType = typeof(Action<>); 
       var parameterType = parameters[0].ParameterType; 
       if (parameterType == actionType) { 
        // this is always false, even if in the debugger both 
        // types are displayed as System.Action`1[T] 
        return true; 
       } 
       return false; 
      }) 
      .FirstOrDefault(); 
    } 
} 

Le problème est que parameterType et actionType ne sont pas égaux, mais quand je vérifie dans le débogueur, ils semblent identiques.

Pourquoi cette comparaison échoue-t-elle?

+0

Avez-vous déboguer? Avez-vous des ** deux ** méthodes? Quel ** est ** 'parameterType' pour chaque méthode? –

+0

Débogage Je reçois deux méthodes comme attendu, et le paramètreType est Action'1 [T] pour les deux. J'ai mis à jour la question. –

+0

Action <>! = Action , Voir Titans réponse – bgura

Répondre

8

Vous devez instancier la définition générique de Action<T> utiliser l'argument générique de la méthode:

var methodTypeArg = m.GetGenericArguments().First(); 
var actionType = typeof(Action<>).MakeGenericType(methodTypeArg); 

Note: Je n'ai pas .NET Core 1.1 dès maintenant à portée de main, j'espère que le api est le même , mais votre problème serait le même dans n'importe quelle version .NET.

La raison pour laquelle vous devez appeler MakeGenericType devient plus évident si vous modifiez le nom de l'argument générique à la méthode:

public void SomeMethod<TMethodArg>(Action<TMethodArg> action) 

Ensuite, il devient plus évident que typeof(Action<>) != typeof(Action<TMethod>). Vous comparez la définition générique de Action<> (qui l'a est sur T) avec une instanciation de cette définition pour l'argument générique (TMethod) de la méthode générique SomeMethod

+0

Je pensais que 'Action ' dans la définition de la méthode et 'Action <>' étaient en fait les mêmes. A condition que cela fonctionne (merci!), Quel est le besoin d'appeler 'MakeGenericType' avec le type d'argument générique? –

+2

@PaoloTedesco J'ai ajouté un peu plus d'explication à la réponse, j'espère que les choses sont plus claires. Fondamentalement, typeof (Action <>) est la définition générique. Les arguments ne sont jamais de ce type, ils ne peuvent être dactylographiés que dans une instanciation de la définition, même si l'instanciation est elle-même liée à un autre argument générique –

+0

Je l'ai maintenant, oui, cela a du sens. Merci encore :) –