C#处置方法
我对C#的“Dispose”模式有困难。我在这里有3个类:管理类、表单类和数据存储类 管理类可以(如果需要)使用表单提示用户输入。表单从文件加载数据,然后用户可以修改该文件。关闭时,表单必须将此数据保存回。数据存储类实现了.Dispose(),它只是将更改写入磁盘 由于此数据存储类(StoredInfo)是表单(MyForm)的成员,因此MyForm还必须实现.Dispose(),以便调用StoredInfo.Dispose。这就是给我带来问题的原因。我的管理类,在其代码中:C#处置方法,c#,.net,dispose,C#,.net,Dispose,我对C#的“Dispose”模式有困难。我在这里有3个类:管理类、表单类和数据存储类 管理类可以(如果需要)使用表单提示用户输入。表单从文件加载数据,然后用户可以修改该文件。关闭时,表单必须将此数据保存回。数据存储类实现了.Dispose(),它只是将更改写入磁盘 由于此数据存储类(StoredInfo)是表单(MyForm)的成员,因此MyForm还必须实现.Dispose(),以便调用StoredInfo.Dispose。这就是给我带来问题的原因。我的管理类,在其代码中: Form.Disp
Form.Dispose();
Form = null;
我的表格:
// As written by MSVS. The exception is OK - I just want this to get called.
#region IDisposable Members
public void IDisposable.Dispose()
{
throw new NotImplementedException();
}
#endregion
…但从未调用Form.Dispose()方法。使用调试器单步执行,执行如下操作:
Connector.Dispose() // The management class
Form.Dispose()
Form.Dispose(bool disposing) // (1) Some method designer wrote?
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
Connector.Dispose() // Back to the management class!
Form = null;
我们不知何故从未调用.Dispose,而是调用了.Dispose(bool)。在C++中,参数可以具有默认值,我可以看到这一点,但是在C语言中,我迷路了。我最好的猜测是,我的调试器没有向我显示实际发生的情况
现在,看一下类层次结构,我看到了实现IDisposable的其他类——因此在某个地方一定有另一个Dispose()成员。它不是虚拟的,所以我不确定为什么我没有得到编译器错误。我尝试重写.Dispose(bool)方法,因为该方法正在被调用,并且是虚拟的,但使用以下方法:
protected override void Dispose(bool disposing)
{
StoredHosts.Dispose();
}
我得到的“类型‘ConnectorForm’已经定义了一个名为‘Dispose’的成员,并且具有相同的参数类型”,是的,我想它确实。。。在设计者的代码中。所以这不是一个选择。现在回到调用Dispose()。但是怎么做呢?现在我忽略了C++析构函数的纯粹的简单性、力量和决定性。 < P>没有规则说你不能干涉设计师的工作,只要你注意不要打破它。可以随意添加到设计器的
Dispose()
方法,也可以删除它并在主源文件中写入一个
设计师不是魔术。它只写普通的C#。表单类(或者确切地说,
组件
类)定义了自己的Dispose
方法,该方法调用虚拟方法Dispose(bool disposing)
您需要将设计器生成的
Dispose
方法(它覆盖虚拟方法并由Component.Dispose
调用)移出设计器文件,然后放入StoredHosts.Dispose()通过编写void IDisposable.Dispose(),您可以有效地告诉运行时,当且仅当变量的类型为IDisposable时,才调用该特定版本的Dispose方法
例如
Windows窗体向导在您不应该修改的代码周围放置了特殊的“区域指令”,因此您可以随意修改Dispose
内容,只要您保持在模式内即可
将IDisposable视为.NET执行析构函数的方式。只要所有实现者都能得到正确的结果,结果就相当于C++析构函数(事实上C++ +CLI从析构函数声明中生成处理方法,而我深深地忽略了C语言中的特征)。
阅读本文了解一些背景知识:
有几件事需要注意。首先,disposing
参数告诉您正在调用Dispose(bool)
virtual方法的wat上下文。如果是false
,则不要做任何事情代码>这意味着正在从终结器线程调用您。这几乎从来没有用过,这是这个模式设计中的一个历史缺陷,因为它有99.99%的有用性(确定性破坏逻辑)和0.01%的有用性(本地资源的自定义自由线程终结)混合在一起,就好像它们是最好的伙伴一样
因此,将自己的清理代码放入if(disposing)
分支中
其次,请注意向导生成的代码在调用对象引用上的Dispose
之前是如何检查对象引用是否为非null的。根据IDisposable
的定义,您应该期望在同一实例上多次调用Dispose
所以你想这样做:
if (Form != null)
{
Form.Dispose();
Form = null;
}
除了“不要用代码编辑器修改此方法的内容”之外,这是另一种方法。当我使用我的方法进行编辑时,设计师是否会破坏我的方法?但是,我发现您需要小心,因为设计师可能会决定覆盖您的更改。如果我最终更改了.designer文件中的某些内容,我会将其移动到.cs文件中,这样当设计器进行更多更改时,它会保留我所更改的内容;大多数情况下,它唯一真正需要处理的是InitializeComponents和与之相关的控件声明,并且您仍然可以修改InitializeComponents——它不会爆炸。我有时会将其更改为初始化控件,而不使用其默认构造函数。但是,如果您向其中添加了其他非常规格式的代码,则该代码可能会被设计器破坏。为什么不刷新关闭事件的数据?@unknown:您应该将其作为一个答案发布-我正在考虑。我在质疑在.Dispose()中执行磁盘I/O的合法性(因为Dispose有点像析构函数,所以不应该在析构函数中引发异常,而我正在做一些可能引发异常的事情。我必须问自己:如果表单剧烈终止(即异常终止)-我想保存数据吗?太好了!我只是用它来处理我的非设计器创建的对象。但是我将该方法从.designer.cs文件中移出,以便更好地实现它,以防设计器将其弄糟。
if (Form != null)
{
Form.Dispose();
Form = null;
}