2 Stimmen

C# Delegaten und Ereignisse?

Ich habe eine Assembly mit einer Klasse, die ein benutzerdefiniertes Ereignis mit einem Delegaten und benutzerdefinierten Ereignisargumenten definiert. Jetzt muss ich diese Assembly dynamisch durch meinen Code laden und eine Instanz dieser Klasse erstellen. Bis hierher bin ich in Ordnung. Jetzt muss ich einen Ereignishandler für das Ereignis bereitstellen, das vom Klassenobjekt ausgelöst wird, und einen benutzerdefinierten Delegaten verwenden. Wie kann ich einen Ereignishandler für das von der Klasse ausgelöste Ereignis mit Reflection hinzufügen?

3voto

Hier ist der Code dazu:

 class Program
  {
    static void Main(string[] args)
    {
      // Erstelle Publisher.
      var pub = Activator.CreateInstance(typeof(Publisher));
      // Hole das Event.
      var addEvent = typeof(Publisher).GetEvent("Event");

      // Erstelle Subscriber.
      var sub = Activator.CreateInstance(typeof(Subscriber));
      // Hole die Methode.
      var handler = typeof(Subscriber).GetMethod("Handle");
      // Erstelle ein gültiges Delegate dafür.
      var handlerDelegate = MakeEventHandlerDelegate(handler, sub);

      // Füge das Event hinzu.
      addEvent.AddEventHandler(pub, handlerDelegate);

      // Rufe die Raise-Methode auf.
      var raise = typeof(Publisher).GetMethod("Raise");
      raise.Invoke(pub, new object[] { "Testwert" });
      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 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 aufgerufen mit {0}.", args.Value);
    }
  }

1voto

John Leidegren Punkte 57871

Ein Ereignis ist ein Multi-Cast-Delegat, Sie würden dieses Ereignis als Typ von System.Delegate abrufen, verwenden Sie Delegate.Combine, um die beiden Instanzen zu kombinieren, und setzen Sie dann den Delegaten auf den kombinierten Delegaten.

C# hat eine praktische verkürzte Syntax dafür:

class SomeClass
{
    public event Action TextEvent;
}

Sie würden etwas in dieser Art schreiben: (Ich bin ein wenig faul und werde das nicht überprüfen, Sie müssen die Fehler selbst herausfinden)

var obj = // Instanz von SomeClass...
var t = typeof(SomeClass); // Sie benötigen das Typobjekt
var member = t.GetEvent("TextEvent");
member.AddEventHandler(obj, new Action(delegate(string s)){}); // Fertig!

0 Stimmen

Das wird nicht funktionieren. Ein Ereignis ist genauso ein Feld wie eine Eigenschaft ein Feld ist. Ereignisse haben add_ und remove_ Methoden (die du wie property get/set definierst, außer dass du add/remove verwendest).

0voto

Kieron Punkte 25804

Ich musste das schon einmal machen, war wirklich mühsam - bin schließlich auf dieses Tutorial gestoßen.

Wäre es möglich, eine Schnittstelle in einer anderen Assembly zu haben, die Sie verwenden könnten, um das Ereignis über Reflexion anzuschließen? Nur so eine Idee...

0voto

Jim Arnold Punkte 2128

Es fehlt mir wahrscheinlich etwas, aber wenn Sie den Namen und die Signatur des Ereignisses kennen, mit dem Sie sich verbinden müssen, wissen Sie in der Regel auch den Typ, der dieses Ereignis freigibt. In diesem Fall, warum müssten Sie Reflektion verwenden? Solange Sie eine korrekt typisierte Referenz haben, können Sie einen Handler auf normale Weise anhängen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X