C# - 超出范围时是否会立即销毁对象?

sha*_*kin 11 c# garbage-collection raii

我是否可以相信一个对象被销毁,并且当它超出C#中的范围时会立即调用它的析构函数?

我认为它应该是因为许多常见的编码实践(例如事务对象)都依赖于这种行为,但我并不习惯使用垃圾收集,并且对这些语言通常的行为方式几乎没有任何了解.

谢谢.

Pet*_*old 27

不,.Net,因此C#依赖于垃圾收集内存管理.因此,在GC发现破坏对象之前,不会调用析构函数(在.Net中称为终结函数).

另外:C#中的大多数"常规"对象没有析构函数.如果需要析构函数模式,则应使用Dispose Pattern实现IDisposable接口.在一次性对象上,您还应该确保调用Dispose方法,使用using关键字或直接调用方法.

进一步(希望)澄清:确定性处理在.Net中很有用,例如当您需要显式释放不由.Net运行时管理的资源时.此类资源的示例是文件句柄,数据库连接等.通常重要的是,一旦不再需要这些资源,就将其释放.因此,我们无法等待GC释放它们.

为了在.Net GC的非确定性世界中获得确定性处理(类似于C++的范围行为),.Net类依赖于IDisposable接口.借用Dispose Pattern,这里有一些例子:

首先,实例化一次性资源,然后让对象超出范围,将其留给GC来处置对象:

1.    {
2.       var dr = new DisposableResource();
3.    }
Run Code Online (Sandbox Code Playgroud)

要解决这个问题,我们可以明确地处理对象:

1.    {
2.       var dr = new DisposableResource();
3.
4.       ...
5.
6.       dr.Dispose();
7.    }
Run Code Online (Sandbox Code Playgroud)

但如果第2行和第6行之间出现问题怎么办?不会调用Dispose.为了进一步确保最终调用Dispose而不管任何例外,我们可以执行以下操作:

1.    var dr = new DisposableResource();
2.    try
3.    {
4.       ...
5.    }
6.    finally
7.    {
8.       dr.Dispose();
9.    }
Run Code Online (Sandbox Code Playgroud)

由于经常需要这种模式,C#包含using关键字以简化操作.以下示例等同于以上示例:

1.    using (var dr = new DisposableResource())
2.    {
3.       ...
4.    }
Run Code Online (Sandbox Code Playgroud)


Age*_*rum 11

不是.对象实际上并不"超出范围",对它的引用(即用于访问它的变量)确实如此.

一旦没有对给定对象的更多引用,该对象就有资格在需要时进行垃圾收集(GC).每当GC决定它需要回收你的不再引用的对象的空间时,就是在调用对象终结器时.

如果您的对象是资源(例如文件句柄,数据库连接),它应该实现IDisposable接口(这使得对象有义务实现Dispose()清理任何打开的连接的方法等).在这种情况下,您的最佳实践是将对象创建为using块的一部分,以便在此块完成时,您的应用程序将自动调用objects Dispose()方法,该方法将负责关闭文件/数据库连接/无论如何.

例如


using (var conn = new DbConnection())  
{ 
   // do stuff with conn  
} // conn.Dispose() is automatically called here.  

Run Code Online (Sandbox Code Playgroud)

using块只是一些语法糖,它包含您与块中conn对象的交互try,以及finally仅调用的块conn.Dispose()