【问题标题】:Dispose on nested Disposable items?处置嵌套的一次性物品?
【发布时间】:2010-07-22 06:19:28
【问题描述】:

我想知道是否有任何关于处理嵌套在另一个一次性物品中的一次性物品的约定(在财产/公共领域,而不是作为私人成员)。例如,DataSet 包含 DataTable(s),SqlCommand 包含 SqlConnection。

很明显,一个类会处理掉它拥有的所有 Disposable 物品,并留下其余的。是否存在这样的约定?如果是,.NET 库如何确定谁拥有什么?如何确定嵌套对象是否正在被释放?

PS:我一直在想这个问题,显然其他人也是如此:What gets disposed when SqlCommand.Dispose is called?

编辑1:发现处理DataSet,不处理它的表。

// Fill dataset from sqldataadpater.
foreach (DataTable dt in dataSet.Tables)
{
    dt.Disposed += Program.DisposedEventHandler2;
}
Console.WriteLine("Disposing dataset");
dataSet.Dispose(); //Event not fired here.
Console.WriteLine("Disposing datatables maually");
foreach (DataTable dt in dataSet.Tables)
{
    dt.Dispose(); //Event fired here
}
#endregion

【问题讨论】:

    标签: c# .net dispose idisposable


    【解决方案1】:

    我通常遵循的经验法则是,创建一次性对象的类也会处理它。举个例子:SqlCommand 没有释放它的连接,因为它没有创建它。 StreamReader 在这个意义上有一个奇怪的行为,因为它总是会处理底层流,即使它是从外部提供的(我觉得这很烦人,如果你喜欢微软来解决这个问题,请投票 HERE)。

    【讨论】:

    • 虽然有时很烦人,但这意味着您可以使用 new StreamReader(new FileStream(...)) 而不必担心有两个 using 语句...这通常可以提高可读性,IMO。
    • @Jon:我理解 BCL 团队为什么选择这种 API 设计。它引导 .NET 开发人员进入“成功的深渊”(正如 Rico Mariani 所说)。但是,我错过了命令StreamReader 使流保持活动状态的枚举或布尔标志的重载。在当前设计中,保持流活动意味着您必须使用 class DoNotDisposeStreamDecorator : Stream 包装流。
    • System.IO.BinaryReader 是最烦人的,有人将流作为输入参数传递给您的一个函数,您选择这个不错的阅读器类来解析二进制数据并结束处理流...
    【解决方案2】:

    我会说通常一个容器会处理所有包含的一次性物品 - 例如,StreamReader 处理底层流 - 但通常我会用单独的using 处理每个物品无论如何声明。

    “所有权”的任何概念实际上都只是在文档和约定中。基本上你必须知道什么会处理什么,这通常意味着阅读文档并希望它说清楚。不幸的是,它并不总是这样做:(

    请注意,这里没有唯一的正确答案 - 有时您可能希望一种类型以一种方式运行,有时另一种方式。某些类型明确允许您说明您是否有效地转移了资源的所有权,尽管大多数都没有。

    【讨论】:

    • 但是,例如,在使用我从查询中读取的数据集时,我是否希望手动处理它包含的数据表(并且数据表包含数据列等等......)?我真的想不出一种优雅的方式来做到这一点。
    • 我主要担心 BCL 库,因为他们的 dispose 方法没有文档,我经常使用它们。
    • @apoorv020: DataTableDataSet 在某种程度上是奇怪的。除非您使用远程处理,否则据我所知,您不需要处理它们。它们实际上只是一次性的,因为它们是可远程控制的。他们从MarshalByValueComponent继承了可处置性。
    • 我向 Microsoft 连接站点添加了关于 StreamReader 类的建议。让我们一起投票:connect.microsoft.com/VisualStudio/feedback/details/577258/…
    • 请注意,如果您同时处理 StreamReader 及其基础流,CodeAnalysis (FxCop) 将向您发出警告 CA2202。 msdn.microsoft.com/en-us/library/ms182334.aspx
    【解决方案3】:

    最好的方法通常是为嵌套的 IDisposable 项提供一个指示,指示是否应将嵌套项与容器一起丢弃,除非该项的使用寿命永远不会超过容器的使用寿命(在这种情况下丢弃容器可以处置该物品),或者可以确定除了容器之外的最后一个需要所装物品的实体将知道它的存在和需要处置(这意味着容器不必担心处置,因为另一个item 可以处理)。

    作为一个简单的例子,假设一个人正在设计一个 UI 框架,并且想要提供一个应该显示Picture 的控件,并提供一种方法,通过该方法代码可以提供要显示的图像。进一步假设某些类型的Picture 具有需要处置的资源。在某些情况下,代码可能希望在多个控件上显示某个 Picture,这些控件可能不会同时被释放。在这种情况下,如果处理一个控件来处理它的图片,那就不好了。另一方面,在其他情况下,代码可能会为显示目的创建图片,将其提供给控件,然后不再关心它。在这种情况下,提供图片的代码可能知道当控件不再需要图片时应该释放它,但可能不知道什么时候会发生。

    使用参数来指示图片是否应为Disposed 将允许在上述两种情况下使用干净的代码。 Winforms 使用的另一种方法是在控件的图片更改或 Image 属性更改时发生事件。将控件的 Image 属性设置为需要处理的图像的代码可以使用这些事件来处理它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-21
      • 2022-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多