2009-03-05 7 views
2

J'ai un assembly avec une classe qui définit un événement personnalisé en utilisant un délégué et des arguments d'événement personnalisés. Maintenant, je dois charger cette assembly dynamiquement à travers mon code et créer l'instance de cette classe. Jusqu'à ici je vais bien. Maintenant, je dois fournir un gestionnaire d'événement à l'événement déclenché par l'objet de classe en utilisant un délégué personnalisé. Comment puis-je ajouter un gestionnaire d'événements à l'événement déclenché à partir de la classe en utilisant Relection?C# Délégations et événements

Répondre

0

Je devais faire cela avant, était une vraie douleur - finalement rencontré tutorial.

Serait-il possible d'avoir une interface dans un autre assemblage que vous pourriez utiliser pour raccorder l'événement avec la réflexion? Juste une pensée ...

1

Un événement est un délégué multidiffusion, vous devez récupérer cet événement en tant que type de System.Delegate utilisez Delegate.Combine pour combiner les deux instances, puis définissez le délégué sur le délégué combiné.

C# a une belle syntaxe abrégée pour cela:

class SomeClass 
{ 
    public event Action<string> TextEvent; 
} 

Vous écrire quelque chose comme ceci: (je me sens un peu paresseux et ne vérifiera pas cela, vous devrez délier les jambes vous)

var obj = // instance of SomeClass... 
var t = typeof(SomeClass); // you need the type object 
var member = t.GetEvent("TextEvent"); 
member.AddEventHandler(obj, new Action<string>(delegate(string s)){}); // done! 
+0

Cela ne fonctionnera pas. Un événement est autant un champ qu'une propriété est un champ. Les événements ont des méthodes add_ et remove_ (que vous définissez comme get/set de la propriété, sauf que vous utilisez add/remove). –

+0

J'ai révisé la réponse, et cela fonctionnera sûrement. –

3

Voici le code pour le faire:

class Program 
    { 
    static void Main(string[] args) 
    { 
     // Create publisher. 
     var pub = Activator.CreateInstance(typeof(Publisher)); 
     // Get the event. 
     var addEvent = typeof(Publisher).GetEvent("Event"); 

     // Create subscriber. 
     var sub = Activator.CreateInstance(typeof(Subscriber)); 
     // Get the method. 
     var handler = typeof(Subscriber).GetMethod("Handle"); 
     // Create a valid delegate for it. 
     var handlerDelegate = MakeEventHandlerDelegate(handler, sub); 

     // Add the event. 
     addEvent.AddEventHandler(pub, handlerDelegate); 

     // Call the raise method. 
     var raise = typeof(Publisher).GetMethod("Raise"); 
     raise.Invoke(pub, new object[] { "Test Value" }); 
     Console.ReadLine(); 
    } 

    static Delegate MakeEventHandlerDelegate(MethodInfo methodInfo, object target) 
    { 
     ParameterInfo[] info = methodInfo.GetParameters(); 
     if (info.Length != 2) 
     throw new ArgumentOutOfRangeException("methodInfo"); 
     if (!typeof(EventArgs).IsAssignableFrom(info[1].ParameterType)) 
     throw new ArgumentOutOfRangeException("methodInfo"); 
     if (info[0].ParameterType != typeof(object)) 
     throw new ArgumentOutOfRangeException("methodInfo"); 

     return Delegate.CreateDelegate(typeof(EventHandler<>).MakeGenericType(info[1].ParameterType), target, methodInfo); 
    } 
    } 

    class Args : EventArgs 
    { 
    public string Value { get; set; } 
    } 

    class Publisher 
    { 
    public event EventHandler<Args> Event; 

    public void Raise(string value) 
    { 
     if (Event != null) 
     { 
     Args a = new Args { Value = value }; 
     Event(this, a); 
     } 
    } 
    } 

    class Subscriber 
    { 
    public void Handle(object sender, Args args) 
    { 
     Console.WriteLine("Handle called with {0}.", args.Value); 
    } 
    } 
0

Je suis probablement manque quelque chose, mais si vous connaissez le nom d'un signature de l'événement auquel vous devez vous connecter, vous connaissez probablement le type qui expose cet événement. Dans ce cas, pourquoi auriez-vous besoin d'utiliser la réflexion? Tant que vous avez une référence correctement typée, vous pouvez attacher un gestionnaire de la manière normale.