我在使用C#的'Dispose'模式时遇到了困难。我在这里有3个课程:管理类,表单和数据存储类。
管理类可以(如果需要)使用表单提示用户输入。表单从文件加载数据,然后用户可以修改该文件。在关闭时,表单必须保存此数据。数据存储类实现.Dispose(),它就是这样做 - 将更改写入磁盘。
由于此数据存储类(StoredInfo)是表单(MyForm)的成员,因此MyForm还必须实现.Dispose()以调用StoredInfo.Dispose。这就是给我带来问题的原因。我的管理类,在它的代码中:
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();
}
我得到“Type'ConnectorForm'已经定义了一个名为'Dispose'的成员,它具有相同的参数类型”,是的,我认为它确实...在Designer的代码中 。所以这不是一个选择。所以回到调用Dispose()。但是怎么样?我现在忽略了C ++析构函数的纯粹简单性和强大功能以及 determinism 。
答案 0 :(得分:4)
Windows窗体向导会在您不应修改的代码周围添加特殊的“区域指令”,因此您可以根据需要修改Dispose
内容,只要您保持在该模式中即可。
将IDisposable视为.NET做析构函数的方式。只要所有实现者都做对了,那么结果就等同于C ++析构函数(实际上C ++ / CLI从析构函数声明中生成Dispose方法,而且我很想念C#中的这个特性)。
请阅读以下背景信息:http://msdn.microsoft.com/en-us/magazine/cc163392.aspx
有几点需要注意。首先,disposing
参数告诉你wat上下文正在调用Dispose(bool)
虚拟方法。如果它是false
,那么DO NOT DO ANYTHING!
这意味着你被调用终结者线程。这几乎从来没有用过,这是这个模式设计的一个历史缺陷,因为它有99.99%有用的东西(确定性破坏逻辑)与只有0.01%有用的东西混合在一起(自定义自由线程完成原生资源)就好像它们一样是最好的朋友。
所以把你自己的清理代码放在if (disposing)
分支中。
其次,请注意向导生成的代码在调用Dispose
之前如何检查对象引用是否为非null。根据{{1}}的定义,您应该在同一个实例上无理由地多次调用IDisposable
。
所以你想这样做:
Dispose
答案 1 :(得分:2)
Form
类(或者,确切地说,Component
类)定义了自己的Dispose
方法,该方法调用虚方法Dispose(bool disposing)
您需要将设计器生成的Dispose
方法(覆盖虚拟方法并由Component.Dispose
调用)移出Designer文件,然后将StoredHosts.Dispose();
放入其中
答案 2 :(得分:1)
没有规则说你不能摆弄设计师的所作所为,只要你注意不要破坏它。随意添加到设计器的Dispose()
方法,或删除它并在主源文件中写一个。
设计师并不神奇。它只写正常的C#。
答案 3 :(得分:0)
通过编写void IDisposable.Dispose(),您可以有效地告诉运行时调用该Dispose方法的特定版本,当且仅当该变量属于IDisposable类型时。
E.g。
Form f1 = new YourForm();
IDispoable f2 = new YourForm();
f1.Dispose(); //call to public void Dispose()
f2.Dispose(); //call to void IDisposable.Dispose()