c# - 我们什么时候应该为组件实现带有 IContainer 参数的构造函数?
问题描述
假设我有一个 WinForms 组件。
它可以是基于System.ComponentModel.Component或System.Windows.Forms.Control类(实际上是Control
继承Component
)的类。
我的组件可能会使用我们应该正确处理的其他 .NET 类——钢笔、画笔、ContextMenuStrips 等。Dispose(bool disposing)
我根据众所周知的IDisposable模式在方法的实现中按预期处置它们。
我想知道,当我必须添加一个接受IConatiner参数的特殊构造函数时,表单设计器将注册我的组件实例,以便在表单关闭期间自动处理资源:
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
...
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
}
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
我分析了一些WinForms Component的方法的源代码Dispose(bool disposing)
试图找到答案,但情况仍然不清楚。
例如,ContextMenuStrip
组件有这样一个构造函数,但DataGridView
没有——尽管两者都有足够的对象在它们的Dispose(bool disposing)
实现中处理。
任何提示或想法?
解决方案
如果您是组件作者,作为最佳实践,我的建议是实现接受的构造函数重载IContainer
,因为当组件具有这样的构造函数时,当开发人员在设计表面上放置组件的实例时,设计人员会生成一段代码关心处理组件。
您的组件在 ToolBox 中可用吗?
对于可以通过工具箱访问的组件,如果用户将组件放在设计器上,那么他们不应该担心组件的处置。所有标准组件都遵循这种模式,用户从不关心他们通过设计器创建的控件和组件的处置,因此组件作者有责任关心设计时支持。
你的组件中有什么要处理的吗?
如果你没有任何东西要处理,那么这个重载并不是那么重要,但是如果你有任何东西要处理,那么你应该关心处理。如前一个要点所述,由于用户可能会将您的组件放在设计器上并依靠设计器来处理它们,因此您有责任提供该方法,以便设计器生成处理代码。否则,组件将不会被释放,从而导致内存/句柄泄漏。
作为组件用户
作为组件用户,如果您在代码中创建组件(而不是在设计时删除它),您有责任在不再需要组件时处理该组件。您可能会发现这篇文章很有用:为什么我应该从设计器中插入非 UI 的 Windows.Forms 组件?
如果您从工具箱中删除了一个组件,那么您不必担心它的处置。所有标准组件都会生成一个代码,以便在处理表单时处理组件。
设计者生成的代码如何处理组件的处置?
对于具有接受的构造函数的组件IContainer
,当您将它们放在设计图面上时,设计器会生成一个代码来创建一个components
集合并将该组件添加到该集合中,然后在表单处置时处置该集合(包括其所有组件)。
查看以下设计器生成的代码:
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
InitializeComponent()
{
this.components = new System.ComponentModel.Container();
...
...
this.myComponent = new MyComponent(this.components);
...
...
}
以及Container类的 Dispose 方法:
protected virtual void Dispose(bool disposing) {
if (disposing) {
lock (syncObj) {
while (siteCount > 0) {
ISite site = sites[--siteCount];
site.Component.Site = null;
site.Component.Dispose();
}
sites = null;
components = null;
}
}
}
您会看到,当您的表单被释放时,它将释放它在容器中找到的所有组件。
推荐阅读
- javascript - Javascript中的自定义方法实现模式
- wso2 - WSO2 API Manager 3.2.0 - 无法删除“服务器”标头
- c++ - WINUI3 - 自定义标题栏
- python - 覆盖 libc open() 导致 python os.popen().read() 挂起
- couchdb - 从 CouchDB 数据库中清除所有非当前数据的推荐过程是什么?
- angular - 描述中定义的变量在角度测试的外部函数中是“未定义的”(jest/jasmine)
- android - Stripe Android - 为错误消息设置区域设置
- php - 使用 curl 和 crontab 执行 api 请求而不是正常工作
- python - 如何在 boto3 中使用 send_raw_email 指定回复?
- ruby-on-rails - Rails::TestUnitReporter 找不到 MiniTest::Result 测试的方法