编写我们自己的Dispose方法而不是使用Idisposable

经过很多Idisposable的文章后,我对它的用法感到困惑。 所有文章都解释了它是什么以及如何实现。 如果我们没有,我想了解我们会想念的。 它是一个接口,其中包含一个方法Dispose()。 让我们举一个例子通常使用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()并释放连接。 为什么在内部实现dispose也调用对象的dispose属性。 作为Idisposable方法的替代方案,我们可以实现释放方法以释放内存。

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

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

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

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

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

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

使用上面的代码将导致在using块的末尾using Dispose() 。 它是一个try语法糖… finally块,但它往往使这种代码更简洁,更容易读写。

  1. 如果您的Release()工作正常(它没有,但这是另一回事),那么人们将不得不了解它,并与另一个类学习其他东西,等等。
  2. 您的Release()永远不会以编程方式找到。 在适用的情况下,可以以编程方式调用Dispose()

    if(obj是IDisposable)((IDisposable)obj)。Dispose();

虽然不常做,但一旦完成,它是至关重要的。

如果有人可能想要在对象使用期间调用它,那么有时候像Release()这样的方法很有用。 一个例子是Stream上的Close() 。 注意这里虽然Stream.Dispose()仍然存在,并调用Close()

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

这意味着维护者不必知道您的特定类的来龙去脉,以防止泄漏资源。 在6个月内,当你忘记了这段代码的大部分内容时,甚至可能是你! 您需要知道的是它实现了IDisposable,它具有通常理解的含义。

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

 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(); 

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

当在using(){…}块的上下文中使用对象时,该接口仅提供任何实际好处。 这样的一个块告诉CLR在它到达块的右括号时调用Dispose方法。 因此,无论在此块中发生什么(没有一些灾难性的系统故障),都可以保证调用Dispose方法并释放您的非托管资源。

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