How to dispose managed resource in Dispose() method in C#?(如何在 C# 的 Dispose() 方法中处理托管资源?)
问题描述
我知道 Dispose() 是为非托管资源设计的,当不再需要该资源时应该将其释放,而无需等待垃圾收集器完成对象.
I know Dispose() is intended for unmanaged resource, and the resource should be disposed when it is no longer needed without waiting for the garbage collector to finalize the object.
但是,在处理对象时,它会抑制垃圾收集器的终结(GC.SuppressFinalize(this); 在下面的代码中).这意味着如果对象包含托管资源,我们也必须注意这一点,因为垃圾收集器不会清理它.
However, when disposing the object, it suppress finalization of the garbage collector (GC.SuppressFinalize(this); in the code below). This means that if the object includes managed resource, we will have to take care of that too because garbage collector will not clean this up.
在下面的示例代码中(来自 MSDN),组件"是一个托管资源,我们为此资源调用 dispose() (component.Dispose()).我的问题是,我们如何为托管资源的 Component 类实现此方法?我们应该使用 Collect() 之类的东西来戳垃圾收集器来清理这部分吗?
In the example code below (from MSDN), "Component" is a managed resource, and we call dispose() for this resource (component.Dispose()). My question is, how do we implement this method for Component class which is managed resource? Should we use something like Collect() to poke garbage collector to clean this portion?
任何想法将不胜感激.谢谢.
Any idea would be appreciated. Thanks.
下面是我正在查看的来自 MSDN 的代码:
Below is the code I'm looking at which is from MSDN:
using System;
using System.ComponentModel;
// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.
public class DisposeExample
{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false;
// The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note disposing has been done.
disposed = true;
}
}
// Use interop to call the method necessary
// to clean up the unmanaged resource.
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
public static void Main()
{
// Insert code here to create
// and use the MyResource object.
}
}
推荐答案
这意味着如果对象包含托管资源,我们也必须注意这一点,因为垃圾收集器不会清理它.
This means that if the object includes managed resource, we will have to take care of that too because garbage collector will not clean this up.
这是错误的.垃圾收集器仍将清理您的托管资源.终结器也严格用于清理非托管资源,因此 SuppressFinalize() 调用不会伤害您.
That is false. The garbage collector will still clean up your managed resources. Finalizers are also strictly for cleaning up unmanaged resources, and so the SuppressFinalize() call won't hurt you.
由于您是 IDisposable 模式的新手,我预计您的下一个困惑点:编写终结器.在 C# 中,您应该只在处理一种全新的非托管资源时编写终结器.因此,例如,如果您有一个将 System.Data.SqlClient.SqlConnection 类型包装为数据访问层的一部分的类,您应该不为该类型编写终结器,因为您仍然处理同一种底层非托管资源:sql server 数据库连接.该资源的终结器已由基本 SqlConnection 类型处理.
And since you are new to the IDisposable pattern I will anticipate your next point of confusion: writing finalizers. In C#, you should only write a finalizer when dealing with a completely new kind of unmanaged resource. So if you have, for example, a class that wraps the System.Data.SqlClient.SqlConnection type as part of a data access layer, you should not write a finalizer for that type because you're still dealing with the same kind of underlying unmanaged resource: sql server database connections. The finalizer for that resource is taken care of already by the base SqlConnection type.
另一方面,如果您正在为一种全新的数据库引擎构建 ADO.Net 提供程序,则需要在连接类中实现终结器,因为以前从未这样做过.
On the other hand, if you're building an ADO.Net provider for a completely new kind of database engine you would need to implement a finalizer in your connection class because that has never been done before.
这篇关于如何在 C# 的 Dispose() 方法中处理托管资源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何在 C# 的 Dispose() 方法中处理托管资源?
基础教程推荐
- 如何激活MC67中的红灯 2022-01-01
- SSE 浮点算术是否可重现? 2022-01-01
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30
- MS Visual Studio .NET 的替代品 2022-01-01
- c# Math.Sqrt 实现 2022-01-01
- 将 XML 转换为通用列表 2022-01-01
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01