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

时间:2010-10-02 11:52:44

标签: c# 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吗?我期待着一个具体的解释。

5 个答案:

答案 0 :(得分:12)

你是对的,使用你的释放方法你会得到完全相同的效果,只要你总是记得打电话。

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

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

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

使用上述代码会导致t Dispose()块末尾的usingtry。它是finally ... {{1}}块的语法糖,但它往往使这种代码更简洁,更易于读写。

答案 1 :(得分:1)

  1. 如果你的Release()工作正常(但不是,但这是另一回事),那么人们就必须了解它,并与其他班级学习其他东西,等等。
  2. 您的Release()无法以编程方式找到。在适用的情况下,可以以编程方式调用Dispose()

    if(obj是IDisposable)   ((IDisposable接口)OBJ).Dispose();

  3. 虽然不常做,但一旦完成,它就至关重要。

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

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:1)

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

答案 4 :(得分:0)

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

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

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