2010-03-06 4 views
5

Langjähriger Joelonsoftware Follower, zum ersten Mal Stackoverflow Poster.Zugriff auf die Eigenschaft Text eines Steuerelements nach dem übergeordneten Formular Dispose() 'd?

Ich will wissen, "wie sicher:" Ich kann die folgende (C#) tun:

Form formDlg = new Form(); 
TextBox box = new TextBox(); 
formDlg.Controls.Add(box); 
formDlg.ShowDialog(); 
formDlg.Dispose(); 
string sUserEntered = box.Text; // After parent Dispose'd! 

In der Praxis wird diese (scheinbar) funktioniert, weil Box (als Steuer) ein private Text Feld (eine Zeichenfolge), die es verwendet, um seine Texteigenschaft zu implementieren, nachdem sein Fensterhandle zerstört wurde.

Ich werde nicht mit einer allgemeinen Antwort zufrieden sein, dass "Sie nicht auf ein Objekt zugreifen können, nachdem es disposed", weil (1) ich kann kein solches Verbot in MS Docs finden, (2) ich bin Zugriff auf eine nicht verwaltete Ressource und (3) dieser Code löst keine Ausnahme aus (einschließlich ObjectDisposedException).

Ich möchte dies tun, damit ich eine kombinierte "ShowAndDispose" -Methode erstellen und verwenden kann, um das Risiko des Vergessens zu reduzieren, immer Dispose() nach ShowDialog() aufzurufen.

Um zu komplizieren, ändert sich das Verhalten im Debugger. Wenn ich vor Dispose() breche; dann Quick Watch Box und Drilldown in seine Control Basisklasse; dann gehe über Dispose() hinaus; dann box.Text gibt "" zurück! In anderen Szenarien gibt box.Text den vom Benutzer eingegebenen Text zurück.

+0

Warum würden Sie eine Dispose auf das Formular erzwingen? Vor allem, wenn Sie nicht auf nicht verwaltete Ressourcen zugreifen. Lassen Sie den Rahmen/GC sich darum kümmern. EDIT: Ich habe das Gefühl, dass Sie eine viel kompliziertere Situation als der Code oben haben. – Zyphrax

+0

Nicht allein, warum greifen Sie auf ein Textfeld in einem Formular zu, das über dispose() ... verfügt? Warum willst du das machen? Macht das keinen Sinn für mich? Das ist wie Zeiger in C, du mallokierst einen Zeiger, machst ein paar Sachen damit, dann befreie es, dann deneferenziere den Zeiger, nachdem er frei ist! – t0mm13b

+0

Zyphrax: Ein Formular enthält viele nicht verwaltete Ressourcen, 1 pro Steuerelement. –

Antwort

2

Es ist ein Detail Implementierung dass dieser Code ausgeführt wird, ohne ein Problem . Die Control.Text-Eigenschaft wird von der Control-Klasse zwischengespeichert, so dass die TextBox keine ObjectDisposed-Ausnahme verursacht.

Das ist relativ selten, viele Steuerelement Eigenschaft Getter und Setter generieren eine Windows-Nachricht das native Window-Steuerelement für den Wert der Eigenschaft zu stellen. Sie erhalten einen Kaboom, weil die Handle-Eigenschaft nicht mehr gültig ist. Beachten Sie auch, dass der Texteigenschaften-Setter den zwischengespeicherten Wert aktualisiert, aber auch eine Window-Nachricht generiert, um das native Steuerelement zu aktualisieren. Kaboom hier.

Ich nehme an, dies ist nur von allgemeinem Interesse, verwenden Sie nie Code wie in Ihrem Programm. Nun, du würdest es schnell genug herausfinden.

+0

Thx, beste Antwort noch. –

1

Der Debugger Szenario mich denken lässt, dass Sie das tun, was nicht zuverlässig ist, um es zu testen sollten Sie zumindest versuchen, diese:

formDlg.Dispose(); 
Application.DoEvents(); 
GC.Collect(); 
GC.WaitForPendingFinalizers(); 
string sUserEntered = box.Text; // After parent Dispose'd! 
+0

OK ich habe es versucht, es funktioniert immer noch. Die formDlg- und die Box-Variablen sind immer noch im Gültigkeitsbereich, daher würde ich nicht erwarten, dass GC ihre Objekte beeinflusst. Thx sowieso. –

+0

@Conrad: Ich bin immer noch zweifelhaft, warum würde der Text im Debugger verschwinden? –

+0

Ich habe etwas getestet und der Text verschwindet mit allen Variationen, die ich versucht habe. Bis ich den Textwert aus dem Steuerelement in eine öffentliche Eigenschaft eingefügt habe, konnte ich den Textwert nicht in mein Hauptformular zurückversetzen - siehe meine Antwort unten. – IAbstract

2

Sie verwenden, um die ‚Verwendung‘ Anweisung ein Objekt, um sicherzustellen, angeordnet wird, wenn Sie sind damit fertig:

frmDialog wird entsorgt werden, sobald der Block gelaufen ist glaube ich.

+0

Ändert seine Frage nicht wirklich. Im Vergleich dazu würde der 'string sUserEntered = box.Text;' nach dem using Block kommen. – Zyphrax

+0

Ja, das ist eine bessere Heilung als eine ShowAndDispose() -Methode. –

+1

@Zyphrax, nein, es würde das OP-Problem über das Vergessen von Dispose und natürlich die Box lösen. Der Textcode würde in die Verwendung gehen. –

0

Ich legte den sUserEntered Wert in eine öffentliche Eigenschaft so auf sie zugegriffen werden kann:

public string UserInput 
    { 
     get; 
     set; 
    } 

    public frmDialog() 
    { 
     // 
     // The InitializeComponent() call is required for Windows Forms designer support. 
     // 
     InitializeComponent(); 

     // 
     // TODO: Add constructor code after the InitializeComponent() call. 
     // 
    } 

    void Button1Click(object sender, EventArgs e) 
    { 
     UserInput = userInput.Text; 
     this.Dispose(); 
    } 

Dann in meiner Hauptform:

 using (dialog = new frmDialog()) 
     { 
      dialog.ShowDialog(); 
      stringUserInput.Text = dialog.UserInput; 
     }; 
+0

Thx, ich weiß, dass ich das tun kann, eine ganz neue Klasse zu erstellen ist viel mehr Extracode als ich möchte. –

0

Es kommt zu mir, kann ich & ein Formular abgeleitete Klasse mit einem BeginShowDialog() -Methode verwenden, erstellen die Anrufe Showdialog() und ein EndShowDialog() -Methode, die ruft Dispose(). Das "Begin" im Methodenname wird die Notwendigkeit für den Aufruf "Ende" offensichtlicher machen.

Ich vermisse C++ 's bestimmte Zerstörung von Einheimischen beim Verlassen des Umfangs.

+0

Sie müssten es immer noch in einen try/finally-Block einbinden, so dass der Gewinn über die Verwendung strittig ist. –

+0

Ich werde den Versuch überspringen/endlich. In dem Fall, in dem ShowDialog() niemals stattfindet, lebe ich mit dem Ressourcenleck. –

+0

Ich stimme nicht zu, dass "using" "das Problem löst", das ich ansprechen möchte, das nie vergessen wird, für die Hunderte von Klassen, die ich verwende, wenn/ob jeder entsorgt werden muss. Wenn ich mich nicht daran erinnern kann, werde ich mich nicht daran erinnern, "using" für diese Klasse zu verwenden, besser als ich daran denke, Dispose() zu nennen. –

Verwandte Themen