经过很多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吗?我期待着一个具体的解释。
答案 0 :(得分:12)
你是对的,使用你的释放方法你会得到完全相同的效果,只要你总是记得打电话。
你应该使用Dispose
/ IDisposable
来做这种事情的原因是一致性。所有.NET开发人员都会知道IDisposable模式,而IDisposable类表示您应处理它,并使用Dispose方法执行此操作。换句话说,使用IDisposable模式会立即告诉另一个开发人员,他应该释放该类所拥有的资源,他应该通过调用Dispose
方法来完成它。
实现IDisposable
的另一个好处是using块,它适用于任何IDisposable类:
using(var t = new Test())
{
// use t
}
使用上述代码会导致t
Dispose()
块末尾的using
被try
。它是finally
... {{1}}块的语法糖,但它往往使这种代码更简洁,更易于读写。
答案 1 :(得分:1)
Release()
工作正常(但不是,但这是另一回事),那么人们就必须了解它,并与其他班级学习其他东西,等等。您的Release()
无法以编程方式找到。在适用的情况下,可以以编程方式调用Dispose()
:
if(obj是IDisposable) ((IDisposable接口)OBJ).Dispose();
虽然不常做,但一旦完成,它就至关重要。
如果可能有人想要在对象使用期间调用它,那么有时像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方法。