Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 处理IDisposable的最佳实践_C#_Idisposable - Fatal编程技术网

C# 处理IDisposable的最佳实践

C# 处理IDisposable的最佳实践,c#,idisposable,C#,Idisposable,我有一个类层次结构,其中的每个成员都可以创建IDisposable对象 我向这个层次结构中的基类添加了一个List属性,我在创建时向其中添加了任何一次性对象。rootDispose方法遍历此列表,并为其列表中的每个项目调用Dispose,然后清除列表。在应用程序中,我显式调用top对象的Dispose方法,使Dispose在层次结构中级联 这是可行的,但是有更好的方法吗?我是否无意中复制了框架中已经存在的一些功能 (注意-所讨论的对象的生存期不允许仅使用块将其包装在中,也不允许使用创建它们的相同

我有一个类层次结构,其中的每个成员都可以创建
IDisposable
对象

我向这个层次结构中的基类添加了一个
List
属性,我在创建时向其中添加了任何一次性对象。root
Dispose
方法遍历此列表,并为其列表中的每个项目调用
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。是的,这很复杂。我的腕管一想到它就坏了。