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++在离开作用域时对局部的破坏。