EventHandler générique

#18   1/12/2010 1:29 PM

Récemment pendant le développement d’un client de test pour un web service, je me suis retrouvé à devoir appeler une même fonction pour tout les évènements *Completed du proxy, le problème est que les EventHandlers du proxy ont tous un prototype différent :

public delegate void PrepareSearchCompletedEventHandler(object sender, PrepareSearchCompletedEventArgs e);

Dans notre cas c’est le 2ème argument qui est typé sur chaque EventHandler.

Quel est l’utilisation pratique d’une telle bidouille ?

Cela me permet simplement de mettre à jour un control avec le contenu SOAP de la réponse du service, un peu comme une fenêtre de log.

Voici la fonction que je souhaite appeler pour chacun de ces évènements :

public void CompletedHandler(object sender, object e);

Et voila comment j’ai fait :



// Pour chaque events

foreach (EventInfo eventInfo in MdfAPIClient.GetType().GetEvents())

{

// Je prends une liste des paramètre du handler

List<Type> param =

(from t in eventInfo.EventHandlerType.GetMethod("Invoke").GetParameters() select t.ParameterType).

ToList();

// J’y ajoute le type qui déclare la fonction que je souhaite appeler

// c’est avec cet argument que l’on passera notre instance

param.Insert(0, typeof(QueryControl));

// Je déclare ma DynamicMethod avec

// le 1er argument est le nom de la méthode pas utile

// le 2nd est le type de retour de cette methode

// le 3ème est le tableau de type d’arguments

// le 4ème le type a qui la méthode sera appropriée

System.Reflection.Emit.DynamicMethod handler = new

DynamicMethod("", typeof(void), param.ToArray(), typeof(QueryControl));

// On recupere le générateur IL

ILGenerator ilGenerator = handler.GetILGenerator();

// Je récupere la méthode que je souhaite appeler ici c’est CompletedHandler du type QueryControl

MethodInfo genHandler = typeof(QueryControl).GetMethod("CompletedHandler");

// Début du contenu de l’event dynamique

// Je re-empile les arguments avec lesquels on m’a appelé (l’instance, le 1er arg (sender), le 2nd arg un type dérivé de EventArgs (e)

ilGenerator.Emit(OpCodes.Ldarg_0);

ilGenerator.Emit(OpCodes.Ldarg_1);

ilGenerator.Emit(OpCodes.Ldarg_2);

// On appel la fonction souhaité

ilGenerator.Emit(OpCodes.Call, genHandler);

// Puis on Retourne

ilGenerator.Emit(OpCodes.Ret);

// Pour finir on ajoute notre eventhandler a notre proxy : MdfAPIClient

eventInfo.AddEventHandler(MdfAPIClient, handler.CreateDelegate(eventInfo.EventHandlerType, queryControl1));

}



Tout ça pour éviter d’écrire :


{

MonProxyWS proxy = new MonProxyWS();


// Puis pour chaque EventHandlers XXX

proxy.XXXCompleted += new XXXCompletedEventHandler(proxy_XXXCompleted);

}


// Ainsi que mon event target différent aussi pour chaque XXX

void proxy_XXXCompleted(object sender, XXXCompletedEventArgs e)

{

queryControl1.CompletedHandler(sender, e);

}




Soit beaucoup de code redondant et sans valeur ajoutée.

Il y a peu être une méthode plus simple ou une implémentation plus claire/propre, dans ce cas laissez un commentaire

 

Edit :

 

Une autre méthode aurait été de faire un Tracelistener qui débite dans le controle voulu, et d'activer les traces network comme ici. Bien sur il existe un tas de trace sources et switches à tous les niveaux, faîtes votre choix.

Categories : Code
Tags : IL, C#, TraceListener

Commentaires

Alex Les commentaires fonctionnent maintenant :)
Vincent PETETIN Voilà une très belle présentation des possibilités que nous offre le framework .NET.

Tu as cependant sous-estimé l'étendu des délégués qui peuvent très bien être attribués à toutes méthodes dont les paramètres est une des classe de base de ceux du délégué et qui renvois une valeur de retour qui dérivent de celui du délégué.

Si la classe Rect dérive de la classe Form, le délégué suivant :
delegate Form CreateHandler(Rect rect);
peut très bien "pointée" sur la méthode suivante :
// accèpte pourquoi pas un objet Rect en paramètre
// et renvois bien une forme
Rect MyCreation(Form form)
{ ... }

L'expression qui suit est donc totalement valide :
CreateHandler creatFunct = MyCreation;

La méthode statique Delegate.CreateDelegate suis cette règle.

Ainsi les lignes suivantes réalisent parfaitement ton test :
EventHandler testHandler = CompletedHandler;
foreach (var eventInfo in MdfAPIClient.GetType().GetEvents())
{
Delegate eventHandler = Delegate.CreateDelegate(eventInfo.EventHandlerType, this,

testHandler.Method);
eventInfo.AddEventHandler(MdfAPIClient, eventHandler);
}


Créer un commentaire

Back to List