Wie kann ich warten, bis ein C# - Ereignis ausgelöst?
Ich habe eine Sender
- Klasse, sendet eine Message
auf eine IChannel
:
public class MessageEventArgs : EventArgs {
public Message Message { get; private set; }
public MessageEventArgs(Message m) { Message = m; }
}
public interface IChannel {
public event EventHandler<MessageEventArgs> MessageReceived;
void Send(Message m);
}
public class Sender {
public const int MaxWaitInMs = 5000;
private IChannel _c = ...;
public Message Send(Message m) {
_c.Send(m);
//wait for MaxWaitInMs to get an event from _c.MessageReceived
//return the message or null if no message was received in response
}
}
Wenn wir Ihnen Nachrichten senden, die IChannel
manchmal eine Antwort gibt, je nachdem, welche Art von Message
gesendet wurde, durch die Erhöhung der MessageReceived
Veranstaltung. Die event-Argumente enthalten, die die Nachricht von Interesse.
Möchte ich Sender.Send()
Methode zu warten, für eine kurze Zeit zu sehen, wenn dieses Ereignis ausgelöst wird. Wenn dem so ist, werde ich zurück sein MessageEventArgs.Message
Eigenschaft. Wenn nicht, ich eine null zurück Message
.
Wie kann ich das warten auf diese Weise? Ich würde es vorziehen, nicht zu haben, tun Sie das threading-Beinarbeit mit ManualResetEvents
und so, kleben regelmäßige event
s wäre optimal für mich.
- "...lieber nicht zu tun haben, das threading-Arbeit..." - Soll das interpretiert werden, wie Sie Ihre app läuft vollständig in einem einzigen thread?
- Nein, mit worker-threads und so ist fein, und Sie sind verwendet an anderer Stelle in der app (zum Beispiel IChannel-Umsetzung erzeugt einen neuen thread zum schreiben in einen stream). Ich möchte bleiben mit der syntaktischen Zucker von Delegaten und Ereignisse, obwohl, und nicht die lower-level -
System.Threading
. - Delegaten und Ereignisse sind nicht syntaktische Zucker für den Durchzug. Ereignisse werden ausgelöst und behandelt, die auf dem gleichen thread (es ist syntaktischer Zucker über einem Funktionsaufruf, und auf die gleiche Weise funktioniert)
- Sorry, ich wollte nicht Ausdrücken, dass sehr gut. In Teil, was ich Frage, ist, ob ich das kann effektiv ein
ManualResetEvent
durch kleben mitevent
s unddelegate
s.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Verwenden
AutoResetEvent
.Gib mir ein paar Minuten und ich werde werfen gemeinsam eine Probe.
Hier ist es:
ManualResetEvents
"), ich hoffe, es gibt eine andere Möglichkeit.BeginInvoke
haben Sie immer noch eine callback-Methode, und Sie haben immer noch die manuelle Synchronisierung des threads irgendwie. Obwohl, das IAsyncResult-Instanz sollte eine WaitHandle für Sie, die würde, die Dinge zu vereinfachen ein wenig, aber nicht viel.Sender.MessageReceived
speichern Sie einige Daten (sagen wir, in einem Instanz-Feld), so dassSender.Send
können es später. (Um dies zu sehen, versuchen, herauszufinden, wie Sie würde wieder etwas anderes als null ausSender.Send
.) Ist es eine eigenständige Art und Weise, es zu tun, aus derSender.Send
Methode?Haben Sie versucht, die Zuordnung der Funktion zum Aufruf asynchron zu einer delegieren, dann beschwört den mydelegateinstance.BeginInvoke?
Linky für die Referenz.
Mit dem unten angeführten Beispiel, rufen Sie einfach
und dann funktioniert es wie von Geisterhand. 🙂
ManualResetEvent
für Sie.EndLoadData
erscheint, um einige der verborgenen Dinge.Sender.Send
Methode, ich Tue das folgende: (1) ordnen Sie dieIChannel.Send
Aufruf eines Delegaten, (2) dann asynchron aufrufen, die mitBeginInvoke
, (3) führen sowohl eine wait-handle und einen Verweis auf den Delegaten aufgerufen wird, (4) dannWaitOne
auf das wait-handle, und (5) weiter auf einmal die.Set
aufgerufen, die Delegierten?Set
? Wenn Sie rief es in die delegieren, wie würden Sie eine Garantie für jede Art von warten? Und wenn Sie immerSleep(timeout)
Sie schlafen werde, egal was, zu besiegen alle das komplizierte einfädeln.Vielleicht Ihre Methode MessageReceived sollte einfach die Flagge, unter der ein Wert für eine Eigenschaft der IChannel-Schnittstelle, die bei der Implementierung von INotifyPropertyChanged event-handler, so dass Sie würde empfehlen, wenn die Eigenschaft geändert wird.
By doing so, Ihre Absender-Klasse konnte Durchlaufen, bis die max Wartezeit abgelaufen ist, oder wenn das PropertyChanged-Ereignis-handler Auftritt, brechen Sie die Schleife erfolgreich. Wenn die Schleife nicht kaputt zu bekommen, dann wird die Nachricht gilt als nie erhalten.
IChannel
Vertrag, das scheint weniger als wünschenswert. Aus einem design-Sicht, ich glaube nicht, dass IChannel sollte zu ändern, da Sie nichts über die Art und Weise Ihrer Implementierung verwenden, es hat sich hier geändert.Nützlich Probe mit AutoResetEvent:
WaitOne
wirklich das richtige Werkzeug für diese Aufgabe. Kurz gesagt, Sie wollen warten, zwischen 0 undMaxWaitInMs
Millisekunden, um einen job zu vervollständigen. Sie haben wirklich zwei Optionen, Umfrage für den Abschluss oder die Synchronisierung der threads mit einigen Konstrukt, das warten kann eine beliebige Menge von Zeit.Da bist du gut bekannt, der richtige Weg, dies zu tun, für die Nachwelt poste ich die polling-version: