关于c#:编写我们自己的Dispose方法而不是使用Idisposable

Writing our own Dispose method instead of using Idisposable

在浏览了很多IDisposable文章之后,我对它的用法感到困惑。所有的文章都解释了它是什么以及如何实现。我想知道如果没有它我们会错过什么。它是一个包含一个方法dispose()的接口。让我们举个例子Dispose的使用通常显示为释放数据库连接。

密码应该是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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?我们可以直接调用这个.databaseConnection.dispose()并释放连接。为什么在内部调用对象的Dispose属性时实现Dispose。除了IDisposable方法之外,我们还可以实现一个释放内存的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Public Class Test
{

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

}
}

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


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

你应该使用DisposeIDisposable来处理这类问题的原因是一致性。所有.NET开发人员都将了解IDisposable模式,而一个IDisposable类指示您应该处理该模式,并使用Dispose方法进行处理。换句话说,使用IDisposable模式会立即告诉另一个开发人员,他应该释放类所拥有的资源,并且应该通过调用Dispose方法来实现。

实现IDisposable的另一个好处是使用块,它在任何IDisposable类上工作:

1
2
3
4
using(var t = new Test())
{
    // use t
}

使用上述代码将导致tusing块的末尾被Dispose()ed。它是tryfinally块的语法糖,但它倾向于使这种代码更简洁,更容易读写。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class DotNetTips    
{    
private void DoSomeOperation()    
{    
using (SqlConnection 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    
}    
}    
}
Using statement is useful when we have to call dispose method multiple times on different objects. Otherwise, we will have to call Dispose method on each object as:


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


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

这意味着维护人员不必知道特定类的进出口来防止资源泄漏。这甚至可能是你,在6个月内,当你忘记了你对这段代码所做的大部分工作时!您只需要知道它实现了IDisposable,这有一个通常理解的含义。

请记住,IDisposable主要是给开发人员的一个信号,"嘿,我是一个保存对非托管资源的引用的类。您可能不应该等待垃圾收集器来清理我。"请注意,这可能是通过组合间接实现的(一个实现IDisposable的类,因为它有实现IDisposable的私有成员)。当一个优秀的开发人员看到一个实现IDisposable的类时,他们应该立即认为"这个对象是特殊的,在我完成它之后需要清理它。"没有什么能阻止您编写release()方法;它只是意味着您更可能意外地泄漏资源,因为您没有使用惯用的patt恩。


  • 如果你的Release()工作正常(这不是,但这是另一回事),那么人们就必须学习它,并在另一门课上学习其他东西,等等。
  • 你的Release()无法通过编程找到。如果适用,可以通过编程调用Dispose()

    如果(obj是IDisposable)(idisposable)obj.dispose();

  • 虽然不是经常做,但当它完成时,它是至关重要的。

    有时,如果可能有人想在对象使用期间调用它,那么拥有一个类似于Release()的方法是很有用的。其中一个例子是Close()on Stream。请注意,虽然Stream.Dispose()仍然存在,并调用Close()


    在将来的某个不确定的点上,托管对象将由垃圾收集自动处理。但是,在处理可能包含非托管资源(不受clr/垃圾收集控制)的对象时,应实现IDisposable,以提供将这些资源返回到操作系统的一致且确定的方法。

    当对象在using()的上下文中使用时,接口只提供任何真正的好处。块。这样的块告诉clr,当Dispose方法碰到块的右大括号时,调用它。因此,无论此块中发生什么(除了一些灾难性的系统故障),都保证调用Dispose方法并释放非托管资源。

    例如,在您提供的代码中,如果引发了异常,则可能永远不会调用您的release()方法,这可能会使连接保持打开状态。但是,当使用带有using块的可释放对象时,当抛出异常时,clr将在抛出异常之前跳入并调用Dispose方法。