在父窗体Dispose()'d之后访问控件的文本属性?

时间:2021-07-08 15:55:05

Long-time joelonsoftware follower, 1st-time * poster.

长期跟踪joelonsoftware, 1次*海报。

I want to know "how safely" I can do the following (C#):

我想知道我能做到以下几点(c#):

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 practice, this (apparently) works, because box (as a Control) has a private text field (a string) which it uses to implement its Text property after its window handle is destroyed.

在实践中,这(显然)是有效的,因为box(作为控件)有一个私有文本字段(字符串),它在窗口句柄被破坏后使用该字段来实现其文本属性。

I won't be satisfied by a general answer that "you can't access an object after it's Disposed" because (1) I can't find any such blanket prohibition in MS docs, (2) I'm not accessing an unmanaged resource, and (3) this code doesn't throw any exception (including ObjectDisposedException).

我不会满足于这样一个一般性的回答:“在对象被处理后,您不能访问它”,因为(1)我在MS docs中找不到任何这样的全面禁止,(2)我没有访问非托管资源,(3)此代码不会抛出任何异常(包括objectdispose sedexception)。

I would like to do this so I can create and use a combined "ShowAndDispose" method to reduce the risk of forgetting to always call Dispose() after ShowDialog().

我想这样做,这样我就可以创建并使用一个组合的“ShowAndDispose”方法,以减少在ShowDialog()之后忘记总是调用Dispose()的风险。

To complicate, the behavior changes in the debugger. If I break before Dispose(); then Quick Watch box and drill down into its Control base class; then step past Dispose(); then box.Text returns ""! In other scenarios box.Text returns the user-entered text.

更复杂的是,调试器中的行为发生了变化。如果在处理之前中断();然后快速观察盒,钻到其控制基类;然后一步过去处理();然后盒子。文本的回报”!在其他场景中框。文本返回用户输入的文本。

5 个解决方案

#1


2  

It is an implementation detail that this code runs without a problem. The Control.Text property happens to be cached by the Control class so disposing the TextBox doesn't cause an ObjectDisposed exception.

这段代码运行时没有问题,这是一个实现细节。的控制。文本属性恰巧被控件类缓存,所以处理文本框不会导致objectdispose异常。

That's fairly rare btw, lots of control property getters and setters generate a Windows message to ask the native Window control for the property value. You'll get a kaboom on those because the Handle property is no longer valid. Notable also is that the Text property setter updates the cached value but also generates a Window message to update the native control. Kaboom here.

顺便说一句,这是相当罕见的,许多控件属性getter和setter会生成一个Windows消息来询问本机窗口控件的属性值。你会得到一个kaboom因为句柄属性不再有效。值得注意的是,文本属性setter会更新缓存的值,但也会生成窗口消息来更新本机控件。大爆炸。

I assume this is just general interest, don't ever use code like that in your program. Well, you'd find out quick enough.

我想这只是一般的兴趣,不要在程序中使用这样的代码。你会很快发现的。

#2


2  

You can use the 'using' statement to ensure an object gets disposed when you're done with it:

你可以使用“使用”语句来确保一个对象在你使用它时被处理:

using(Form frmDialog = new Form())
{
    //Do stuff
}

frmDialog will get disposed once the block has run I believe.

frmDialog在块运行后会被处理。

#3


1  

The debugger scenario makes me think that what you do is not reliable, to test it you should at least try this:

调试器场景使我认为您所做的是不可靠的,为了测试它,您至少应该尝试以下方法:

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

#4


0  

I put the sUserEntered value into a public property so it could be accessed:

我将suserenter输入的值放入公共属性,以便可以访问:

    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();
    }

Then in my mainform:

然后在我mainform:

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

#5


0  

It occurs to me, I can create & use a Form-derived class with a BeginShowDialog() method which calls ShowDialog(), and an EndShowDialog() method which calls Dispose(). The "Begin" in the method name will make the need for the "End" call more obvious.

我想到,我可以创建和使用一个表单派生的类,它有一个BeginShowDialog()方法,调用ShowDialog(),还有一个EndShowDialog()方法,调用Dispose()。方法名中的“Begin”将使“End”调用的需要更加明显。

I miss C++'s determinate destruction of locals on leaving scope.

我怀念c++在离开作用域时对局部的破坏。

#1


2  

It is an implementation detail that this code runs without a problem. The Control.Text property happens to be cached by the Control class so disposing the TextBox doesn't cause an ObjectDisposed exception.

这段代码运行时没有问题,这是一个实现细节。的控制。文本属性恰巧被控件类缓存,所以处理文本框不会导致objectdispose异常。

That's fairly rare btw, lots of control property getters and setters generate a Windows message to ask the native Window control for the property value. You'll get a kaboom on those because the Handle property is no longer valid. Notable also is that the Text property setter updates the cached value but also generates a Window message to update the native control. Kaboom here.

顺便说一句,这是相当罕见的,许多控件属性getter和setter会生成一个Windows消息来询问本机窗口控件的属性值。你会得到一个kaboom因为句柄属性不再有效。值得注意的是,文本属性setter会更新缓存的值,但也会生成窗口消息来更新本机控件。大爆炸。

I assume this is just general interest, don't ever use code like that in your program. Well, you'd find out quick enough.

我想这只是一般的兴趣,不要在程序中使用这样的代码。你会很快发现的。

#2


2  

You can use the 'using' statement to ensure an object gets disposed when you're done with it:

你可以使用“使用”语句来确保一个对象在你使用它时被处理:

using(Form frmDialog = new Form())
{
    //Do stuff
}

frmDialog will get disposed once the block has run I believe.

frmDialog在块运行后会被处理。

#3


1  

The debugger scenario makes me think that what you do is not reliable, to test it you should at least try this:

调试器场景使我认为您所做的是不可靠的,为了测试它,您至少应该尝试以下方法:

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

#4


0  

I put the sUserEntered value into a public property so it could be accessed:

我将suserenter输入的值放入公共属性,以便可以访问:

    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();
    }

Then in my mainform:

然后在我mainform:

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

#5


0  

It occurs to me, I can create & use a Form-derived class with a BeginShowDialog() method which calls ShowDialog(), and an EndShowDialog() method which calls Dispose(). The "Begin" in the method name will make the need for the "End" call more obvious.

我想到,我可以创建和使用一个表单派生的类,它有一个BeginShowDialog()方法,调用ShowDialog(),还有一个EndShowDialog()方法,调用Dispose()。方法名中的“Begin”将使“End”调用的需要更加明显。

I miss C++'s determinate destruction of locals on leaving scope.

我怀念c++在离开作用域时对局部的破坏。