Ich habe einen Hintergrund-Thread, der die Benutzeroberfläche aktualisiert, sobald es fertig ist. Ich habe versucht, so sicher wie möglich zu sein, damit ich nicht die GUI anrufe, die Disposed ist.UI vom Hintergrund Thread aktualisieren - woher weiß ich, dass meine GUI nicht entsorgt wird?
void DoInBackground()
{
try
{
string result = ServerSideProcess();
* if (!IsDisposed && !Disposing)
* BeginInvoke(new StringDelegate(UpdateText), result);
}
catch (Exception ex)
{
* if (!IsDisposed && !Disposing)
* BeginInvoke(new VoidDelegate(UpdateFailed));
}
}
void UpdateText(string txt)
{
if (!IsDisposed && !Disposing)
textbox1.Text = txt;
}
void UpdateFailed()
{
if (!IsDisposed && !Disposing)
textbox1.Text = "failed to get data from server";
}
override Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
components.Dispose();
}
base.Dispose(disposing);
}
Ich denke, dass ich genug, um in die GUI-Methoden sicher bin - Entsorgen() wird nicht aufgerufen, während ich innen Update (string) oder UpdateFailed(), weil sie laufen beide im selben Thread bin, also nehme ich an, dass die Überprüfung auf IsDisposing und spätere Ausführung gut genug ist. Aber wie kann ich sicher sein, dass die Teile in (*) kein Dispose() dazwischen bekommen, was dazu führen wird, dass BeginInvoke für eine disponierende Klasse aufgerufen wird und schließlich ein Anwendungsabsturz?
Ich testete es, indem ich Thread.Sleep (2000) zwischen den (*) Teilen hinzufügte, Breakpoints vor und nach dem Thread.Sleep platzierte und aus dem Steuerelement löste, um Dispose() d zu erhalten, bevor BeginInvoke erreicht wurde. das Ergebnis - meine Bewerbung ist abgestürzt. Wie kann ich wissen, dass die Laufzeit mir dieses unglückliche Kontextwechsel-Szenario nicht geben wird?
Es gibt einige unglückliche Macken in der Art, wie 'InvokeRequired', 'BeginInvoke' usw. implementiert werden, so dass es keine rennfreie Freigabe gibt, wenn Sie keine gesperrte Flagge innerhalb Ihrer' Dispose'-Routine setzen können Möglichkeit, ein 'BeginInvokeUnlessWindowIsGone' auszuführen. Sie müssen nur das 'BeginInvoke' machen und die Ausnahme verschlucken. – supercat
@supercat stimmte zu, deshalb denke ich, es ist ein Ausnahmefall (und so ist der Versuch/Fang gerechtfertigt). –
Von einer Anruferseite, ja. Es ist ein kleines Design, aber der Gestank kommt von dem Versagen des Frameworks zu erkennen, dass viele BeginInvokes (und Ereignisse) zugunsten des Ziels statt des Aufrufers geschehen; Ähnliches passiert bei Ereignissen (z. B. weil es kein "WeakEvent" oder "WeakDelegate" gibt). – supercat