为什么我们需要可识别的对象

本文关键字:识别 对象 我们 为什么 | 更新日期: 2023-09-27 18:34:49

我来自C++背景,很难理解IDisposable对象的意义(以及 .NET 中许多其他事物的意义(。为什么首先需要Dispose函数?不管它做什么,为什么不在类的析构函数中这样做呢?我知道它会清理托管资源,但这不是析构函数应该做的吗?我明白

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

相当于

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

但是这如何节省任何打字?如果 C# 有一个垃圾回收器,它确实有,那么我们为什么要担心释放资源呢?

IDisposable/Using/etc. 是双向飞碟批准的概念吗?他怎么看?

为什么我们需要可识别的对象

IDisposable没什么特别的。它只是一个让你拥有Dispose()功能的界面。 IDisposable不会清除任何东西或破坏物体。如果 Dispose() 函数不执行任何操作,则对该函数的调用不执行任何操作。

IDisposable的使用是一种模式。它是如此重要,以至于它有自己的语言结构(using块(,但它只是一个模式。

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

因此,IDisposable确定地释放不需要的引用(以及释放非托管资源(是存在的。调用 Dispose 后,"已释放"对象将保留在内存中,直到垃圾回收器决定收集它(此时,将调用"析构函数",除非您明确告诉它不要这样做(,如果它决定这样做(。

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

至于我们为什么需要它:

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

至于using块,它更等同于:

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

所以它确实节省了打字

使用 using 块不仅会调用 .Dispose 方法,还会调用 .离开块时处理方法,但你离开它。 因此,如果您的代码崩溃,它仍将调用 Dispose。 实际代码将更接近:

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

此外,析构函数并不总是在预期时触发。 我遇到了一些错误,在程序显然退出后调用析构函数,并尝试访问不再存在的资源。 由于您不know何时调用它,因此很难解决此问题。