【问题标题】:C# - I know, I know, another question about Dispose (more related to design)!C# - 我知道,我知道,关于 Dispose 的另一个问题(与设计更相关)!
【发布时间】:2011-01-02 02:39:00
【问题描述】:

可能重复:
Should I Dispose() DataSet and DataTable?

OP 评论:我想说“我应该 Dispose() DataSet 和 DataTable 吗?”链接不是一个可能的解决方案。这是一个很好的链接,但这与设计有关。相反,请忽略公开的属性是 DataSet 并将其替换为应处置的内容。同样的问题也适用于那里。

我在搞乱水晶报表,我有一个“ReportData”类。换句话说,这个类封装了我将使用的 DataSet 的“填充”。

public class ReportData
{
    private DataSet1 m_DS = null; // Notice this disposable member variable

    public ReportData( ... some parameters ...)
    {
        m_DS = new DataSet1();
        // Plus some other manipulation on m_DS
    }

    public DataSet1 GetDataSet
    {
        get
        {
            return m_DS;
        }
    }

    // Everything else is pretty much private.
    // This class is here to generate my DataSet
}

这是其他类如何使用它的:

private void SetReportDataSource()
{
    DataSet1 ds = m_RptData.GetDataSet;
    m_Rpt.SetDataSource(ds);
}

我几乎是在快速学习 C#(阅读了一本介绍书中的几章,然后就开始学习,一路上用谷歌搜索所有内容)。据我了解,如果它实现了 IDisposable,你最好 Dispose 它。一个DataSet实现了IDisposable,所以我们需要Dispose它。

这里是设计部分的用武之地:

问题 1a:我是否将 ReportData 类设为 IDisposable?

换句话说,看起来我可以这样做并完成它:

private void SetReportDataSource()
{
    using (DataSet1 ds = m_RptData.GetDataSet)
    {
        m_Rpt.SetDataSource(ds);
    }
}

问题 1b:我是否应该在某种程度上更具防御性?

我不知道,我想我真的,真的在努力确保它得到处理。例如,以我的 SetReportDatsSource 函数为例。我使用了“using”,但其他人可能会使用该类而忘记添加 using 或以某种方式调用 Dispose。因此,我去我的 ReportData 类:

public class ReportData : IDisposable
{
    private DataSet1 m_DS = null; // Notice this disposable member variable
    private bool m_IsDisposed = false; // This is new!

    public ReportData( ... some parameters ...)
    {
        m_DS = new DataSet1();
        // Plus some other manipulation on m_DS
    }

    // New code here (up until the GetDataSet property)
    ~ReportData()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (m_IsDisposed == true)
        {
            return;
        }

        if (m_DS != null)
        {
            m_DS.Dispose();
            m_DS = null;
        }

        m_IsDisposed = true;
    }

    // Done with new code

    public DataSet1 GetDataSet
    {
        get
        {
            return m_DS;
        }
    }

    // Everything else is pretty much private.
    // This class is here to generate my DataSet
}

现在,让我们回到调用类,我们还有:

private void SetReportDataSource()
{
    using (DataSet1 ds = m_RptData.GetDataSet)
    {
        m_Rpt.SetDataSource(ds);
    }
}

但是,我现在也将 ReportData (m_RptData) 设为一次性!所以,我们要处理掉它!而且因为它是一个成员变量(我不能像在 SetReportDataSource 中那样使用“using”),你开始考虑让这个调用类 IDisposable,所以我可以:

    protected virtual void Dispose(bool disposing)
    {
        if (m_IsDisposed == true)
        {
            return;
        }

        if (m_ReportData != null)
        {
            m_ReportData.Dispose();
            m_ReportData = null;
        }

        m_IsDisposed = true;
    }

所以,现在这个类具有析构函数/终结器及其公共 Dispose 方法,用于处理 ReportData。我们保证会处理掉 DataSet!

但话又说回来,这将导致 DataSet 的 Dispose 方法被调用两次。因为 SetReportDataSource 函数释放了暴露的 DataSet,而 ReportData 类也在释放同样的东西(并且没有简单的方法来确定是否有人释放了暴露的 DataSet)。

看起来有点疯狂。在我看来,我:

a) 可能是想多了(或者只是想真正防御,这很好)!

b) 可能会跳过一堆箍。

也许规则应该是:如果我的类要公开它,调用函数应该负责处理它。

我看到的唯一问题(这就是我在这里发布的原因):

在实例化 ReportData 成员变量和调用 SetReportDataSource 之间,可能会发生一些错误/异常。因此,我们永远没有机会对我们的数据集进行“使用”(在 SetReportDataSource 内部)。但是那个数据集是用 ReportData 构建的(我们想在它上面调用 dispose!)

所以,现在我们回到制作 ReportData IDisposable 的过程中,因为我们至少需要一些公共的“CleanUp”功能......好吧,我完成了。 :)

【问题讨论】:

  • 我想说“我应该 Dispose() DataSet 和 DataTable 吗?”链接不是一个可能的解决方案。这是一个很好的链接,但这与设计有关。相反,请忽略暴露的属性是一个 DataSet 并将其替换为应该被释放的东西。
  • 有人投票将其关闭为“公然冒犯”?埃加德。
  • 也许这与你争论的语气和你荒谬的标题有关?你那长得不值一提的帖子怎么样?您在帖子中使用的格式缺失或可笑的表情如何?我想知道为什么有人不会觉得这令人反感。
  • @Chet A - 我不道歉;它们略有不同(您会注意到关闭它的也是我,以添加交叉引用)
  • @JustLooking - 你在这里问了一些非常冗长的问题,这让人们很难理解。我认为,如果您可以使问题更...具体,您将获得更多有用的答案。

标签: c# dispose


【解决方案1】:

如果您持有实现 IDisposable 的东西,最简单的模式是自己实现 IDisposable,然后在您拥有的所有 IDisposable 上调用 Dispose 方法。比看起来不可行的更具防御性;如果有人使用你的类忘记调用你的 Dispose 方法,那么你怎么知道他们已经使用你了?

编辑:再想一想,Finalize 调用告诉您,您的客户已经使用您了;他们不再提及你...

【讨论】:

    【解决方案2】:

    请看:Should I Dispose() DataSet and DataTable?

    正如在 SO 上多次出现的那样,如果一个对象实现了 IDisposable,那么您应该调用 Dispose()。 [在 .NET 框架中有几个地方,原始设计者可能需要 Dispose() 但后来不需要它。但最安全和正确的做法是无论如何都调用 Dispose。]

    【讨论】:

    • 这是一个有用的链接,谢谢。但是让我们忽略这是一个数据集的事实。它可能是别的东西,我不知道,一个字体(我暴露的)。同样的讨论也适用。诚然,我的模式是:如果它有一个 Dispose 方法,我想调用它。相反:它有一个 Dispose 方法,让我在世界上搜索一下它是否真的有什么作用。现在,我需要做得更好一些,弄清楚这些人是如何调试 C# 源代码的,以确定 Dispose 真的没用……而且……唷!但是谢谢,很好的链接。并为您 +1。
    【解决方案3】:

    您没有显示SetDataSource 的代码,但只有当SetDataSource 立即使用DataSet 的内容并且不存储对它的引用时,这段代码才会起作用:

    private void SetReportDataSource()
    {
        using (DataSet1 ds = m_RptData.GetDataSet)
        {
            m_Rpt.SetDataSource(ds);
        }
    }
    

    至于您的其余代码和问题(引用已删除的答案):


    您没有任何需要完成的事情。您可能已经注意到,当您发现 disposing 参数没有用处时。你只需要这个:

    void Dispose() {
      if (m_DS != null) m_DS.Dispose()
    }  
    

    终结器的一般规则是:如有疑问,请不要。
    当您直接使用非托管资源时,您只需要一个。

    【讨论】:

      【解决方案4】:

      答案 1A:我建议使用 using 语法,原因是它似乎是处理此类事物的标准。

      答案 1B:如果其他人正在使用您的类,我假设您的意思是扩展,实现者需要处理他认为合适的任何更改。根据 Dispose() 上的文档

      如果多次调用对象的 Dispose 方法,则对象必须忽略第一次调用之后的所有调用。如果多次调用其 Dispose 方法,则该对象不得引发异常。如果由于资源已被释放并且之前未调用过 Dispose 而发生错误,则 Dispose 可以引发异常。 (http://msdn.microsoft.com/en-us/library/system.idisposable.dispose%28VS.71%29.aspx)

      垃圾收集器会在某个时候获取您的对象并处理它。除非发生灾难。

      【讨论】:

      • 回应的要点(我担心我可能不得不使用 DataSet 以外的其他东西重新发布这个问题)。至于1B,我的意思不是延伸。我的意思是调用类实例化 ReportData,然后再使用它(在我看来,其中一个问题是实例化......在我使用 using 之前发生异常/错误)。
      • 那么在这种情况下会发生异常,这无关紧要。 GC 应该得到它,因为没有可用的有效引用
      • (响应的另一点)实际上,我的意思是:ReportData 被实例化(因此,DataSet 确实 - DataSet 是一次性的)。一切都好。稍后,在某些其他事件中,会发生错误。由于这个错误,我们永远不会调用 SetReportDataSource。现在,我们需要处理 ReportData/DataSet。我不是在谈论实际实例化期间的异常。我们只依赖于在 SetDataSource 中使用“using”(处理 DataSet),但是如果在完成的实例化和 SetDataSource 之间的某个时刻发生错误,那该怎么办?
      • 假设异常一直向上传播并且程序终止。垃圾收集器应该解决这个问题,但是在某些情况下可能会发生内存泄漏。但是,如果您只是吞下异常,就会出现问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-12
      • 2023-02-04
      相关资源
      最近更新 更多