MSDN关于如何实现Dispose

2024-03-15 18:38
文章标签 实现 msdn dispose

本文主要是介绍MSDN关于如何实现Dispose,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

类型的 Dispose 方法应该释放它拥有的所有资源。它还应该通过调用其父类型的 Dispose 方法释放其基类型拥有的所有资源。该父类型的 Dispose 方法应该释放它拥有的所有资源并同样也调用其父类型的 Dispose 方法,从而在整个基类型层次结构中传播该模式。要确保始终正确地清理资源,Dispose 方法应该可以被多次安全调用而不引发任何异常。

Dispose 方法应该为它处置的对象调用 GC.SuppressFinalize 方法 。如果对象当前在终止队列中,GC.SuppressFinalize 防止其 Finalize 方法被调用。请记住,执行 Finalize 方法会大大减损性能。如果您的 Dispose 方法已经完成了清理对象的工作,那么垃圾回收器就不必调用对象的 Finalize 方法了。

下面的代码示例旨在阐释如何为封装了非托管资源的类实现 Dispose 方法的一种可能的设计模式。因为该模式是在整个 .NET Framework 中实现的,所以您可能会发现它十分便于使用。但是,这不是 Dispose 方法唯一可能的实现。

资源类通常是从复杂的本机类或 API 派生的,而且必须进行相应的自定义。使用这一代码模式作为创建资源类的一个起始点,并根据封装的资源提供必要的自定义。不能编译该示例,也不能将其直接用于应用程序。

在此示例中,基类 BaseResource 实现可由类的用户调用的公共 Dispose 方法。而该方法又调用 virtual Dispose(bool disposing) 方法(Visual Basic 中为 virtual Dispose(disposing As Boolean))。根据调用方的标识传递“真”或“假”。以虚 Dispose 方法为对象执行适当的清理代码。

Dispose(bool disposing) 以两种截然不同的方案执行。如果“处置”等于“真”,则该方法已由用户的代码直接调用或间接调用,并且可处置托管资源和非托管资源。如果“处置”等于“假”,则该方法已由运行库从终结器内部调用,并且只能处置非托管资源。因为终结器不会以任意特定的顺序执行,所以当对象正在执行其终止代码时,不应引用其他对象。如果正在执行的终结器引用了另一个已经终止的对象,则该正在执行的终结器将失败。

基类提供的 Finalize 方法或析构函数在未能调用 Dispose 的情况下充当防护措施。Finalize 方法调用带有参数的 Dispose 方法,同时传递“假”。不应在 Finalize 方法内重新创建 Dispose 清理代码。调用 Dispose(false) 可以优化代码的可读性和可维护性。

MyResourceWrapper 阐释如何使用 Dispose 从实现资源管理的类派生。MyResourceWrapper 重写 virtual Dispose(bool disposing) 方法并为其创建的托管和非托管资源提供清理代码。MyResourceWrapper 还对其基类 BaseResource 调用 Dispose 以确保其基类能够适当地进行清理。请注意,派生类 MyResourceWrapper 没有不带参数的 Finalize 方法或 Dispose 方法,因为这两个方法从基类 BaseResource 继承它们。

注意   此示例中的 protected Dispose(bool disposing) 方法不强制线程安全,因为无法从用户线程和终结器线程同时调用该方法。另外,使用 BaseResource 的客户端应用程序应从不允许多个用户线程同时调用 protected Dispose(bool disposing) 方法。应用程序或类库的设计原则为:应用程序或类库应只允许一个线程拥有资源的生存期,以及在不再需要资源时调用 Dispose。根据资源的不同,在处置资源时进行异步线程访问可能会带来安全风险。开发人员应仔细检查自己的代码,以确定最佳的方法来强制线程安全。

 

// Design pattern for the base class.
// By implementing IDisposable, you are announcing that instances
// of this type allocate scarce resources.
public class BaseResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component Components;
// Track whether Dispose has been called.
private bool disposed = false;
// Constructor for the BaseResource object.
public BaseResource()
{
// Insert appropriate constructor code here.
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// Take yourself off the Finalization queue 
// to 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.
protected virtual 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.
Components.Dispose();
}
// Release unmanaged resources. If disposing is false, 
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note that this is not thread safe.
// Another thread could start disposing the object
// after the managed resources are disposed,
// but before the disposed flag is set to true.
// If thread safety is necessary, it must be
// implemented by the client.
}
disposed = true;         
}
// 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.
~BaseResource()      
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
// Allow your Dispose method to be called multiple times,
// but throw an exception if the object has been disposed.
// Whenever you do something with this class, 
// check to see if it has been disposed.
public void DoSomething()
{
if(this.disposed)
{
throw new ObjectDisposedException();
}
}
}
// Design pattern for a derived class.
// Note that this derived class inherently implements the 
// IDisposable interface because it is implemented in the base class.
public class MyResourceWrapper: BaseResource
{
// A managed resource that you add in this derived class.
private ManagedResource addedManaged;
// A native unmanaged resource that you add in this derived class.
private NativeResource addedNative;
private bool disposed = false;
// Constructor for this object.
public MyResourceWrapper()
{
// Insert appropriate constructor code here.
}
protected override void Dispose(bool disposing)
{
if(!this.disposed)
{
try
{
if(disposing)
{
// Release the managed resources you added in
// this derived class here.
addedManaged.Dispose();         
}
// Release the native unmanaged resources you added
// in this derived class here.
CloseHandle(addedNative);
this.disposed = true;
}
finally
{
// Call Dispose on your base class.
base.Dispose(disposing);
}
}
}
}
// This derived class does not have a Finalize method
// or a Dispose method without parameters because it inherits 
// them from the base class.

 

实现 Close 方法

对于类型来说,若调用 Close 方法比调用 Dispose 方法更简易,则可以向基类型添加一个公共 Close 方法。Close 方法又调用没有参数的 Dispose 方法,该方法可以执行正确的清理操作。下面的代码示例阐释了 Close 方法。

 

// Do not make this method virtual.
// A derived class should not be allowed
// to override this method.
public void Close()
{
// Calls the Dispose method without parameters.
Dispose();
} 

这篇关于MSDN关于如何实现Dispose的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/812893

相关文章

Nginx实现高并发的项目实践

《Nginx实现高并发的项目实践》本文主要介绍了Nginx实现高并发的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录使用最新稳定版本的Nginx合理配置工作进程(workers)配置工作进程连接数(worker_co

python中列表list切分的实现

《python中列表list切分的实现》列表是Python中最常用的数据结构之一,经常需要对列表进行切分操作,本文主要介绍了python中列表list切分的实现,文中通过示例代码介绍的非常详细,对大家... 目录一、列表切片的基本用法1.1 基本切片操作1.2 切片的负索引1.3 切片的省略二、列表切分的高

基于Python实现一个PDF特殊字体提取工具

《基于Python实现一个PDF特殊字体提取工具》在PDF文档处理场景中,我们常常需要针对特定格式的文本内容进行提取分析,本文介绍的PDF特殊字体提取器是一款基于Python开发的桌面应用程序感兴趣的... 目录一、应用背景与功能概述二、技术架构与核心组件2.1 技术选型2.2 系统架构三、核心功能实现解析

使用Python实现表格字段智能去重

《使用Python实现表格字段智能去重》在数据分析和处理过程中,数据清洗是一个至关重要的步骤,其中字段去重是一个常见且关键的任务,下面我们看看如何使用Python进行表格字段智能去重吧... 目录一、引言二、数据重复问题的常见场景与影响三、python在数据清洗中的优势四、基于Python的表格字段智能去重

Spring AI集成DeepSeek实现流式输出的操作方法

《SpringAI集成DeepSeek实现流式输出的操作方法》本文介绍了如何在SpringBoot中使用Sse(Server-SentEvents)技术实现流式输出,后端使用SpringMVC中的S... 目录一、后端代码二、前端代码三、运行项目小天有话说题外话参考资料前面一篇文章我们实现了《Spring

Nginx中location实现多条件匹配的方法详解

《Nginx中location实现多条件匹配的方法详解》在Nginx中,location指令用于匹配请求的URI,虽然location本身是基于单一匹配规则的,但可以通过多种方式实现多个条件的匹配逻辑... 目录1. 概述2. 实现多条件匹配的方式2.1 使用多个 location 块2.2 使用正则表达式

使用Apache POI在Java中实现Excel单元格的合并

《使用ApachePOI在Java中实现Excel单元格的合并》在日常工作中,Excel是一个不可或缺的工具,尤其是在处理大量数据时,本文将介绍如何使用ApachePOI库在Java中实现Excel... 目录工具类介绍工具类代码调用示例依赖配置总结在日常工作中,Excel 是一个不可或缺的工http://

SpringBoot实现导出复杂对象到Excel文件

《SpringBoot实现导出复杂对象到Excel文件》这篇文章主要为大家详细介绍了如何使用Hutool和EasyExcel两种方式来实现在SpringBoot项目中导出复杂对象到Excel文件,需要... 在Spring Boot项目中导出复杂对象到Excel文件,可以利用Hutool或EasyExcel

Python如何实现读取csv文件时忽略文件的编码格式

《Python如何实现读取csv文件时忽略文件的编码格式》我们再日常读取csv文件的时候经常会发现csv文件的格式有多种,所以这篇文章为大家介绍了Python如何实现读取csv文件时忽略文件的编码格式... 目录1、背景介绍2、库的安装3、核心代码4、完整代码1、背景介绍我们再日常读取csv文件的时候经常

Golang中map缩容的实现

《Golang中map缩容的实现》本文主要介绍了Go语言中map的扩缩容机制,包括grow和hashGrow方法的处理,具有一定的参考价值,感兴趣的可以了解一下... 目录基本分析带来的隐患为什么不支持缩容基本分析在 Go 底层源码 src/runtime/map.go 中,扩缩容的处理方法是 grow