为什么我们需要可识别的对象
本文关键字:识别 对象 我们 为什么 | 更新日期: 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# 中称为(的主要区别。
至于我们为什么需要它:
- 对其他对象的托管引用可防止垃圾回收器收集对象。因此,您需要"释放"这些引用(例如,通过将引用这些对象的变量设置为
null
(。 - 如果 .NET 中的对象使用本机库,则可以使用非托管资源。例如,
Windows.Forms
应用程序中的每个控件或位图都使用非托管Win32 handler
。如果不释放这些资源,则在使用任何大型应用程序时,可能会轻松达到Windows中的句柄限制。此外,如果您需要与任何 non-.NET API 的互操作性,则更有可能必须分配非托管内存(例如,使用Marshal.AllocHGlobal
(,这将需要在某个时候释放:该点通常是IDisposable
的Dispose()
函数,必须显式调用(或使用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
何时调用它,因此很难解决此问题。