Utilisation de la reflection pour spécifier le type d’un délégué (à attacher à un événement)?

Ce que je veux réellement faire est quelque chose comme ceci (je réalise que ce n’est pas un code valide):

// Attach the event. try { EventInfo e = mappings[name]; (e.EventHandlerType) handler = (sender, raw) => { AutoWrapEventArgs args = raw as AutoWrapEventArgs; func.Call(this, args.GetParameters()); }; e.AddEventHandler(this, handler); } ... 

Maintenant, je sais que le e.EventHandlerType sera toujours dérivé de EventHandler . Cependant, je ne peux pas simplement faire:

  EventHandler handler = (sender, raw) => { AutoWrapEventArgs args = raw as AutoWrapEventArgs; func.Call(this, args.GetParameters()); }; e.AddEventHandler(this, handler); 

Comme .NET se plaint qu’aucune conversion n’est applicable de EventHandler à EventHandler lorsque AddEventHandler est appelé. C’est le message exact:

 Object of type 'System.EventHandler`1[IronJS.AutoWrapObject+AutoWrapEventArgs]' cannot be converted to type 'System.EventHandler`1[Node.net.Modules.Streams.NodeStream+DataEventArgs]'. 

J’ai également essayé d’utiliser Invoke pour utiliser de manière dynamic le constructeur de e.EventHandlerType, mais il n’existe aucun moyen de passer la définition du délégué à la liste de parameters de Invoke () (car il n’y a pas de conversion de délégué en object).

Est-il possible d’utiliser la reflection pour résoudre ce problème?

Bingo! L’astuce consiste à obtenir une référence au constructeur pour le type de délégué, puis de l’invoquer à l’aide des parameters suivants:

  • L’object cible du délégué (backend.Target)
  • Le pointeur du délégué (backend.Method.MethodHandle.GetFunctionPointer ())

Le code qui en résulte ressemble à ceci (t dans ce cas, l’argument générique fourni à EventHandler <> pendant l’héritage):

 Type t = e.EventHandler.GetGenericArguments()[0]; Delegate handler = (Delegate) typeof(EventHandler<>) .MakeGenericType(t) .GetConstructors()[0] .Invoke(new object[] { backend.Target, backend.Method.MethodHandle.GetFunctionPointer() }); 

Vous pouvez ensuite utiliser le délégué pour l’événement en ajoutant comme suit:

 e.AddEventHandler(this, handler); 

Vous pouvez utiliser Delegate.CreateDelegate pour atteindre votre objective comme ceci:

 public void RegisterHandler(ssortingng name) { EventInfo e = mappings[name]; EventHandler handler = (s, raw) => { func.Call(this, raw.GetParameters()); }; e.AddEventHandler(this, Delegate.CreateDelegate(e.EventHandlerType, null, handler.Method)); }