2

我在使用 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();
}

我得到“类型'ConnectorForm'已经定义了一个具有相同参数类型的名为'Dispose'的成员”,是的,我想它确实......在Designer's code中。所以这不是一个选择。所以回到调用 Dispose()。但是怎么做?目前,我正在怀念 C++ 析构函数的纯粹简单、强大和确定性

4

4 回答 4

4

Windows 窗体向导在您不应该修改的代码周围放置了特殊的“区域指令”,因此您可以随意修改这些Dispose内容,只要您保持在模式内。

将 IDisposable 视为 .NET 执行析构函数的方式。只要所有实现者都做对了,那么结果就可以等同于 C++ 的析构函数(实际上 C++/CLI 从析构函数声明中生成了 Dispose 方法,我非常怀念 C# 中的那个特性)。

阅读本文了解一些背景:http: //msdn.microsoft.com/en-us/magazine/cc163392.aspx

有几件事需要注意。首先,disposing参数告诉您正在调用虚拟方法的上下文Dispose(bool)。如果是false,则DO NOT DO ANYTHING!表示您正在从终结器线程中调用。这几乎从来没有用过,这是该模式设计中的一个历史缺陷,因为它混合了 99.99% 有用的东西(确定性破坏逻辑)和只有 0.01% 有用的东西(本地资源的自定义自由线程终结),就好像它们是最好的朋友。

所以把你自己的清理代码放在if (disposing)分支里面。

其次,请注意向导生成的代码在调用它之前如何检查对象引用是否为非空Dispose。根据 的定义IDisposable,您应该期望Dispose在同一个实例上无缘无故地被调用多次。

所以你想这样做:

if (Form != null)
{
    Form.Dispose();
    Form = null;
}
于 2009-06-10T06:52:28.147 回答
2

Form(或者,准确地说,Component类)定义了自己的Dispose方法,该方法调用了虚方法Dispose(bool disposing)

您需要将设计器生成的Dispose方法(它覆盖虚拟方法并由 调用Component.Dispose)移出设计器文件,然后放入StoredHosts.Dispose();其中。

于 2009-06-09T18:32:10.670 回答
1

没有规则说你不能摆弄设计师所做的事情,只要你注意不要破坏它。随意添加到设计器的Dispose()方法中,或者删除它并在主源文件中编写一个。

设计师不是魔术师。它只是编写普通的 C#。

于 2009-06-09T18:24:24.193 回答
0

通过编写 void IDisposable.Dispose(),当且仅当变量的类型为 IDisposable 时,您有效地告诉运行时调用该特定版本的 Dispose 方法。

例如

Form f1 = new YourForm();
IDispoable f2 = new YourForm();

f1.Dispose(); //call to public void Dispose()
f2.Dispose(); //call to void IDisposable.Dispose()
于 2009-06-10T06:30:19.160 回答