C# 处理IDisposable的最佳实践
我有一个类层次结构,其中的每个成员都可以创建C# 处理IDisposable的最佳实践,c#,idisposable,C#,Idisposable,我有一个类层次结构,其中的每个成员都可以创建IDisposable对象 我向这个层次结构中的基类添加了一个List属性,我在创建时向其中添加了任何一次性对象。rootDispose方法遍历此列表,并为其列表中的每个项目调用Dispose,然后清除列表。在应用程序中,我显式调用top对象的Dispose方法,使Dispose在层次结构中级联 这是可行的,但是有更好的方法吗?我是否无意中复制了框架中已经存在的一些功能 (注意-所讨论的对象的生存期不允许仅使用块将其包装在中,也不允许使用创建它们的相同
IDisposable
对象
我向这个层次结构中的基类添加了一个List
属性,我在创建时向其中添加了任何一次性对象。rootDispose
方法遍历此列表,并为其列表中的每个项目调用Dispose
,然后清除列表。在应用程序中,我显式调用top对象的Dispose
方法,使Dispose在层次结构中级联
这是可行的,但是有更好的方法吗?我是否无意中复制了框架中已经存在的一些功能
(注意-所讨论的对象的生存期不允许仅使用块将其包装在中,也不允许使用创建它们的相同方法对其进行处理。)
编辑
我只是想澄清一下,我只是把那些需要保留的东西放在身边。有些是以创建它们的相同方法处理的,但许多是以不可能的方式使用的。只要您正确地实现一次性模式(如上所述),这种方法就可以了
据我所知,只有using
语句对IDisposable
有特殊的支持-框架中没有任何东西可以复制您正在做的事情。如果您谈论的是任意的IDisposable
对象,我认为它不存在
System.ComponentModel.Container
类实现级联Dispose,但需要元素来实现IComponent
。如果您控制您的IDisposable
对象,您可以让它们实现IComponent
——它只需要实现一个属性站点
,该属性可以返回空值不正确IDisposable
旨在释放非托管资源,应在完成实例后尽快调用。这是一种常见的误解,认为这是不必要的,或者当对象被垃圾收集时,finalizer将自动执行此操作。事实并非如此
IDisposable
的正确模式如下所示,并包含在下面以供快速参考
public class Resource : IDisposable
{
// Dispose() calls Dispose(true)
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// NOTE: Leave out the finalizer altogether if this class doesn't
// own unmanaged resources itself, but leave the other methods
// exactly as they are.
~Resource()
{
// Finalizer calls Dispose(false)
Dispose(false);
}
// The bulk of the clean-up code is implemented in Dispose(bool)
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// free managed resources
}
// free native resources here if there are any
}
}
听起来这是一种模式可能是合适的情况。尽管我从不理解这样的说法,即它扩展了您的类并保持它们不变,因为我只知道一些示例,其中类应该有一个AcceptVisitor
方法或类似的方法。顺便说一句,这不是我喜欢的模式,因为它很复杂,而且容易使代码混乱。如果一个对象将创建许多其他可识别的对象,并在其存在的整个过程中保持它们的所有权,那么您描述的模式可能是一个很好的模式。它可以通过让类实现方法“T regdisp(T thing),其中T:IDisposable;”来增强,该方法将向列表中添加一个一次性的,并返回它。因此,可以将“someField=somedisposetype.CreateThing();”之类的语句替换为“someField=regdisp(somedisposetype.CreateThing());”,从而在同一语句中创建和清理资源
如果您的类不公开公共构造函数(要求外部人员使用工厂方法),并且如果您使用的是vb.net或愿意使用线程静态字段,您甚至可以将初始化和清理与声明结合起来(例如,“var someField=regdispose(someDisposType.CreateThing());”)。为了安全起见,必须在try/catch或try/finally块中调用构造函数,如果构造失败,该块可以对创建的子对象调用Dispose。因为C#中的字段初始值设定项无法访问构造函数参数(语言中的一个弱点,IMHO)实现这种模式的唯一方法是让factory方法创建列表,并将其放入线程静态变量中,然后通过静态regdisp方法读取该变量。为什么有这么多的IDisposable
s?我正在创建和维护大量非托管资源-映像,etc-由非托管代码进行带外更新。我不确定这是一个好主意-IComponent
接口用于RAD设计器中使用的非可视组件,这在一般类层次结构中似乎不太可能。@Greg,我指出它的存在,而不是针对给定场景推荐它。但是如果你认为这不是一个好主意,也许你可以解释为什么?@Joe good info。我应该提到,其中一些在compact框架上运行,其中IComponent似乎不受支持。@Joe-正如我所说,实现IComponent
表示对象可以在RAD设计器中使用(即作为windows窗体上的组件删除)并且应该为该场景提供相关的设计时支持。对于大多数类层次结构来说,情况可能并非如此。有关详细信息,请阅读及其链接页面。@Greg-获得此信息非常有用,因为它有助于评估建议是否适用于给定场景。在这种情况下,我仍然不确定-框架中有IComponent类,它们主要不用于RAD设计器-例如System.Diagnostics.Process。是的,这很复杂。我的腕管一想到它就坏了。