Gibt es eine nette einfache Methode, um einen Funktionsaufruf zu verzögern, während der Thread weiter ausgeführt wird?
z.B
public void foo()
{
// Do stuff!
// Delayed call to bar() after x number of ms
// Do more Stuff
}
public void bar()
{
// Only execute once foo has finished
}
Ich bin mir bewusst, dass dies mit einem Timer und Ereignishandlern erreicht werden kann, aber ich habe mich gefragt, ob es einen Standardweg gibt, um dies zu erreichen.
Wenn jemand neugierig ist, ist der Grund dafür, dass foo () und bar () in verschiedenen (Singleton-) Klassen sind, die ich unter außergewöhnlichen Umständen gegenseitig aufrufen muss. Das Problem ist, dass dies bei der Initialisierung erfolgt, sodass foo bar aufrufen muss, das eine Instanz der erstellten foo-Klasse benötigt ... daher der verzögerte Aufruf von bar (), um sicherzustellen, dass foo vollständig instanziiert ist. Lesen Sie dies zurück fast riecht nach schlechtem Design!
BEARBEITEN
Ich werde die Punkte über schlechtes Design unter Hinweis nehmen! Ich habe lange gedacht, dass ich das System verbessern könnte, aber diese schlimme Situation tritt nur auf, wenn eine Ausnahme ausgelöst wird, zu allen anderen Zeiten existieren die beiden Singletons sehr gut nebeneinander. Ich denke, ich werde mich nicht mit fiesen Async-Mustern herumschlagen, sondern die Initialisierung einer der Klassen umgestalten.
Awake
undStart
Phasen. In derAwake
Phase konfigurieren Sie sich selbst und am Ende dieser Phase werden alle Objekte initialisiert. Während derStart
Phase können die Objekte miteinander kommunizieren.Antworten:
Dank modernem C # 5/6 :)
quelle
Ich habe selbst nach so etwas gesucht - ich habe mir Folgendes ausgedacht, obwohl es einen Timer verwendet, ihn nur einmal für die anfängliche Verzögerung verwendet und keine
Sleep
Anrufe erfordert ...(Danke an Fred Deschenes für die Idee, den Timer innerhalb des Rückrufs zu entsorgen)
quelle
timer
lokale Variable aus dem Lambda heraus verwenden, die an das Delegatenobjekt gebunden wird,cb
wird sie in einen anon-Speicher (Detail der Abschlussimplementierung) gehievt, wodurch dasTimer
Objekt aus Sicht des GC erreichbar ist, solange derTimerCallback
Delegat selbst erreichbar ist . Mit anderen Worten, esTimer
wird garantiert , dass das Objekt erst dann mit Müll gesammelt wird, wenn das Delegatenobjekt vom Thread-Pool aufgerufen wird.Abgesehen davon, dass ich den Entwurfsbeobachtungen der vorherigen Kommentatoren zustimmte, war keine der Lösungen für mich sauber genug. .Net 4 bietet
Dispatcher
undTask
Klassen, die die Verzögerung der Ausführung im aktuellen Thread ziemlich einfach machen:Für den Kontext verwende ich dies, um eine
ICommand
an eine linke Maustaste gebundene Schaltfläche auf einem UI-Element zu entprellen . Benutzer doppelklicken, was alle Arten von Chaos verursachte. (Ich weiß, dass ich auchClick
/DoubleClick
handler verwenden könnte, aber ich wollte eine Lösung, die auf ganzer Linie mitICommand
s funktioniert ).quelle
Es klingt so, als ob die Kontrolle über die Erstellung dieser beiden Objekte und ihre gegenseitige Abhängigkeit extern und nicht zwischen den Klassen selbst gesteuert werden muss.
quelle
Es ist in der Tat ein sehr schlechtes Design, geschweige denn Singleton an sich ist schlechtes Design.
Wenn Sie die Ausführung jedoch wirklich verzögern müssen, können Sie Folgendes tun:
Dies wird jedoch
bar()
in einem separaten Thread aufgerufen. Wenn Siebar()
den ursprünglichen Thread aufrufen müssen, müssen Sie möglicherweise denbar()
Aufruf an denRunWorkerCompleted
Handler verschieben oder ein bisschen hackenSynchronizationContext
.quelle
Nun, ich müsste dem "Design" -Punkt zustimmen ... aber Sie können wahrscheinlich einen Monitor verwenden, um einen zu informieren, wenn der andere den kritischen Abschnitt überschritten hat ...
quelle
Verwendung:
quelle
Ich denke, die perfekte Lösung wäre, einen Timer für die verzögerte Aktion zu haben. FxCop mag es nicht, wenn Sie ein Intervall von weniger als einer Sekunde haben. Ich muss meine Aktionen verzögern, bis mein DataGrid die Sortierung nach Spalten abgeschlossen hat. Ich dachte, ein One-Shot-Timer (AutoReset = false) wäre die Lösung, und er funktioniert perfekt. UND, FxCop lässt mich die Warnung nicht unterdrücken!
quelle
Dies funktioniert entweder mit älteren Versionen von .NET
Cons: wird in einem eigenen Thread ausgeführt
Verwendung:
quelle
Es gibt keine Standardmethode, um einen Aufruf einer Funktion zu verzögern, außer einen Timer und Ereignisse zu verwenden.
Dies klingt wie das GUI-Anti-Muster zum Verzögern eines Aufrufs einer Methode, damit Sie sicher sein können, dass das Formular vollständig angelegt wurde. Keine gute Idee.
quelle
Aufbauend auf der Antwort von David O'Donoghue finden Sie hier eine optimierte Version des verzögerten Delegierten:
Die Klasse könnte durch Verwendung eines eindeutigen Schlüssels für die Delegierten etwas verbessert werden. Wenn Sie denselben Delegaten ein zweites Mal hinzufügen, bevor der erste ausgelöst wurde, tritt möglicherweise ein Problem mit dem Wörterbuch auf.
quelle
quelle