为什么我们需要IDisposable对象?

时间:2016-02-16 08:07:01

标签: c# .net

我来自C ++背景,无法理解IDisposable对象的观点(以及.NET中许多其他内容的要点)。为什么首先需要Dispose函数?无论它做什么,为什么不在类的析构函数中做到这一点?我理解它可以清理托管资源,但这不是析构函数应该做的吗?我明白了

Using ( var obj = new SomeIDisposableObject ) 
{
    // ...
} 

相当于

var obj = new SomeIDisposableObject;
// ...
obj.Dispose();

但是如何保存任何打字?如果C#有一个垃圾收集器,那么为什么我们会担心处理资源呢?

IDisposable / Using /等。 Skeet认可的概念?他怎么看待它?

2 个答案:

答案 0 :(得分:7)

tableView(tableView: UITableView, numberOfRowsInSection section: Int) numberOfSectionsInTableView(tableView: UITableView) tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 没什么特别的。它只是一个让你拥有IDisposable功能的界面。 Dispose()无法清除任何内容或销毁对象。如果该函数什么都不做,对IDisposable的调用什么也不做。

使用Dispose()模式。它是如此重要以至于它获得了自己的语言结构(IDisposable块),但它只是一种模式。

与析构函数的区别在于,在.NET中,析构函数是非确定性的。你永远不知道垃圾收集器什么时候会收集你的对象。你甚至不知道它是否会(不像在C ++中使用using,这是确定性的。)

所以delete确定性释放不需要的引用(以及释放非托管资源)。 "处理"在调用IDisposable之后,对象将保留在内存中,直到垃圾收集器决定收集它(此时,将调用"析构函数"除非您明确告诉它不要),如果它决定了。

这是使用"析构函数"的主要区别。 (或终结者,因为它们在C#中调用)。

至于为什么我们需要它:

  1. 对其他对象的托管引用会阻止垃圾回收器收集对象。所以你需要"发布"那些引用(例如,通过将引用这些对象的变量设置为Dispose)。
  2. .NET中的对象可以使用非托管资源(如果它们使用本机库)。例如,null应用程序中的每个控件或位图都使用Windows.Forms,这是非托管的。如果您不发布这些资源,则可以轻松地在Windows中使用任何大型应用程序时达到句柄限制。此外,如果您需要与任何非.NET API的互操作性,您更有可能必须分配非托管内存(例如,使用Win32 handler),这需要在某些内容中释放point:该点通常 Marshal.AllocHGlobal Dispose() IDisposable函数,必须明确调用(或使用using块)。
  3. 对于using块,它更相当于:

    var myObject = new MyDisposableClass();
    try
    {
      ...
    } 
    finally {
      myObject.Dispose();
    }
    

    所以确实可以节省打字

答案 1 :(得分:1)

使用using块并不只调用.Dispose方法;当你离开街区时它会调用.Dispose方法,但是你留下它。因此,如果您的代码崩溃,它仍将调用Dispose。实际代码将更接近:

try
{
    var obj = new SomeIDisposableObject;
    // ...
}
catch (exception ex)
{
}
finally
{
    obj.Dispose();
}

此外,析构函数并不总是在您期望的时候触发。我已经有一些错误,在程序显然退出后调用析构函数,并尝试访问不再存在的资源。由于你不会know何时会被召唤,因此很难解决这个问题。