【问题标题】:Writing our own Dispose method instead of using Idisposable编写我们自己的 Dispose 方法而不是使用 Idisposable
【发布时间】:2010-10-02 11:52:44
【问题描述】:

看了很多关于IDisposable的文章后,我对它的用法感到困惑。所有文章都解释了它是什么以及如何实现它,但我想了解如果我们没有它会错过什么。

这是实现IDisposable 的类的示例。 dispose 的使用通常显示为释放数据库连接。

public class Test : IDisposable
{
    public Test()
    {
        DatabaseConnection databaseConnection = new DatabaseConnection();
    }

    public void Dispose()
    {
        if (this.databaseConnection != null)
        {
            this.databaseConnection.Dispose();
            this.databaseConnection = null;
        }
    }
}

虽然实现了Dispose(),但在Dispose()方法内部,databaseConnection的dispose属性用于释放连接(this.databaseConnection.Dispose();)。

我的问题是为什么在这种情况下我们需要实现IDisposable我们可以直接调用this.databaseConnection.Dispose()并释放连接。 IDisposable内部也调用对象的Dispose()方法,为什么还要实现呢?

替代IDisposable的方法,我们可以实现一个方法Release()来释放内存。

public class Test
{
    public Test()
    {
        DatabaseConnection databaseConnection = new DatabaseConnection();
    }

    public void Release()
    {
        if (this.databaseConnection != null)
        {
            this.databaseConnection.Dispose();
            this.databaseConnection = null;
        }
    }
}

这两种方法有什么区别?我们真的需要IDisposable吗?我期待一个具体的解释。

【问题讨论】:

  • 代码很不对,需要是类的私有成员,而不是构造函数的局部变量。

标签: c# idisposable


【解决方案1】:

你是对的,使用你的 Release 方法你会得到完全相同的效果,只要你总是记得调用它。

您应该使用Dispose / IDisposable 进行此类事情的原因是一致性。所有 .NET 开发人员都知道 IDisposable 模式,并且 IDisposable 的类表示您应该处理它,并使用 Dispose 方法来处理它。换句话说,使用 IDisposable 模式会立即告诉另一个开发人员,他应该释放类持有的资源,并且应该通过调用 Dispose 方法来完成。

实现IDisposable 的另一个好处是 using 块,它适用于任何 IDisposable 类:

using(var t = new Test())
{
    // use t
}

使用上面的代码将导致tusing 块的末尾被Dispose()ed。它是try...finally 块的语法糖,但它倾向于使这种代码更简洁,更易于阅读和编写。

【讨论】:

  • 除了一致性之外,您是否看到任何其他使用 Idisposable 的激励因素
  • @Piyush - 不允许客户端程序员在语言中使用关键字是相当大的事情,远远超出了一致性。
  • 我想说 .NET 对象契约的一个基本部分,即对象应尽量遵守的,是在放弃之前的对象清理除了调用 @ 之外不需要任何操作987654331@ [对于没有实现IDisposable 的类,不需要任何操作]。尽管IDisposable 是一个接口,但它应该更多地被视为Object 契约的一部分,特别是因为具体类没有 实现IDisposable 的事实更多地是关于类比它确实
【解决方案2】:
  1. 如果您的 Release() 工作正常(它不能正常工作,但那是另一回事),那么人们将不得不了解它,并通过其他课程学习其他内容,等等。
  2. 您的Release() 永远无法以编程方式找到。可以通过以下方式以编程方式调用Dispose()

    if(obj is IDisposable)
      ((IDisposable)obj).Dispose();
    

虽然不常做,但做起来很重要。

当有人可能想在对象使用期间调用它时,拥有像 Release() 这样的方法有时很有用。这方面的一个例子是Close() 上的Stream。请注意,尽管Stream.Dispose() 仍然存在,并且会调用Close()

【讨论】:

    【解决方案3】:
    public class DotNetTips
    {
        private void DoSomeOperation()
        {
            using (var con1 = new SqlConnection("First Connection String"),
                       con2 = new SqlConnection("Second Connection String"))
            {
                // Rest of the code goes here
            }
        }
    
        private void DoSomeOtherOperation()
        {
            using (SqlConnection con = new SqlConnection("Connection String"))
            using (SqlCommand cmd = new SqlCommand())
            {
                // Rest of the code goes here
            }
        }
    }
    

    当我们必须在不同的对象上多次调用Dispose() 方法时,using 语句很有用。否则,我们将不得不在每个对象上调用它:

    if (con != null) con.Dispose();
    if (cmd != null) cmd.Dispose();
    

    【讨论】:

      【解决方案4】:

      IDisposable 值得实现,主要是因为它在 C# 中是惯用的。每个人都知道IDisposable 做了什么,以及如何处理实现了IDisposable 的对象。当您使用 IDisposable.Dispose() 以外的其他方式释放资源时,您就偏离了普遍理解的习惯用法。

      这意味着维护者不必知道特定类的来龙去脉来防止资源泄漏。这甚至可能是你,在 6 个月内,你已经忘记了你对这段代码所做的大部分工作!你只需要知道它实现了IDisposable,它有一个普遍理解的含义。

      请记住,IDisposable 主要是给开发人员的一个信号,“嘿,我是一个包含对非托管资源的引用的类。你可能不应该等待垃圾收集器清理我。”请注意,这可能是通过组合间接实现的(实现IDisposable 的类,因为它具有实现IDisposable 的私有成员)。当一个体面的 C# 开发人员看到一个实现 IDisposable 的类时,他们应该立即认为“这个对象很特别,当我完成它时需要清理它。”没有什么可以阻止您编写Release() 方法;这只是意味着您更有可能意外泄漏资源,因为您没有使用惯用模式。

      【讨论】:

        【解决方案5】:

        托管对象将在未来某个不确定的时间点通过垃圾收集自动处置。但是,在处理可能拥有非托管资源(不受 CLR/垃圾回收控制)的对象时,应实现 IDisposable 接口以提供将这些资源返回给操作系统的一致且确定性的方法。

        只有在 using() { ... } 块的上下文中使用对象时,该接口才能提供任何真正的好处。这样的块告诉 CLR 在遇到块的右大括号时调用 Dispose 方法。所以无论这个块内发生什么(没有一些灾难性的系统故障),你的 Dispose 方法一定会被调用并且你的非托管资源被释放。

        例如,在您提供的代码中,如果引发异常,则您的 Release() 方法可能永远不会被调用,从而可能使连接保持打开状态。但是,当在 using 块中处理一次性对象时,当抛出异常时,CLR 会在抛出异常之前跳入并调用您的 Dispose 方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-20
          • 1970-01-01
          • 2018-02-11
          • 1970-01-01
          相关资源
          最近更新 更多