理解C#和C++/CLI中的IDisposable实现

在处理资源管理时,C#C++/CLI提供了不同的机制来确保资源被正确释放。本文将探讨如何在这两种语言中实现IDisposable接口,并分析它们在资源管理方面的异同。

C#中的IDisposable实现

C#中,实现IDisposable接口是一种常见的资源管理方式。以下是一个简单的C#类,它实现了IDisposable接口,并且处理了托管资源和非托管资源。

namespace DisposeDemo { public class CsDisposableBase : IDisposable { public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~CsDisposableBase() { Dispose(false); } protected virtual void Dispose(bool disposing) { if (disposing) { DisposeManagedResources(); } FreeNativeResources(); } private void DisposeManagedResources() { Console.WriteLine("Disposing managed resources in base class"); } private void FreeNativeResources() { Console.WriteLine("Freeing native resources in base class"); } public CsDisposableBase(String name) { this.Name = name; } public String Name { get; private set; } protected void WriteLine(String text) { Console.WriteLine("{0} : {1}", this.Name, text); } } }

在C#中,任何继承此类的开发者都需要重写并实现Dispose(bool)方法,以满足类的要求。

C++/CLI中的IDisposable实现

C++/CLI中,实现IDisposable接口并不像在C#中那样直观。C++/CLI不允许类中有名为Dispose的方法。但是,可以通过以下方式来实现它:

namespace CppDisposable { public ref class DisposableDerived : CsDisposableBase { private: void DisposeManagedResourcesDerived() { WriteLine("Disposing managed resources in derived class"); } void FreeNativeResourcesDerived() { WriteLine("Freeing native resources in derived class"); } public: ~DisposableDerived() { DisposeManagedResourcesDerived(); this->!DisposableDerived(); } !DisposableDerived() { FreeNativeResourcesDerived(); } DisposableDerived(String^ name) : CsDisposableBase(name) { } }; }

这段代码看起来可能有些问题,但如何确保基类的Dispose方法(以及析构函数)在需要时被调用呢?让写一些测试代码来看看会发生什么。

int main(array^ args) { CppDisposable::DisposableDerived object1("Object that gets disposed"); CppDisposable::DisposableDerived^ object2 = gcnew CppDisposable::DisposableDerived("Object that gets GCd"); return 0; }

运行这段代码,会看到以下输出:

哇,一切都工作得很好。这是怎么回事呢?答案在于VC++编译器的魔法。使用Reflector查看生成的代码,可以看到编译器为生成了可能需要自己编写的代码。

Reflector中的生成代码

以下是Reflector中看到的生成代码:

protected override void Dispose([MarshalAs(UnmanagedType.U1)] bool flag1) { if (flag1) { try { this->~DisposableDerived(); } finally { base.Dispose(true); } } else { try { this->!DisposableDerived(); } finally { base.Dispose(false); } } }

在Dispose调用期间,以下情况会发生:

  • C#基类Dispose调用Dispose(true)并抑制GC。
  • C++/CLI实现调用~DisposableDerived(释放派生类中的托管资源,然后调用!DisposableDerived释放派生类中的非托管资源)。
  • 现在调用base.Dispose(true)(在finally块中)释放基类中的托管和非托管资源。

在最终化期间,以下情况会发生:

  • C#基类析构函数调用Dispose(false)。
  • C++/CLI实现调用!DisposableDerived(释放派生类中的非托管资源)。
  • 现在调用base.Dispose(false)(在finally块中)释放基类中的非托管资源。

本质上,这段代码正是需要编写的——编译器为生成了它。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485