在 C++/CLI 中,ref 类析构函数是对 Dispose pattern 的抽象。
编译后的以下 C++/CLI 类:
public ref class Test
{
public:
Test() { System::Console::WriteLine("ctor"); }
~Test() { System::Console::WriteLine("dtor"); }
static void Foo()
{
auto foo = gcnew Test();
foo->~Test();
}
};
反编译为以下 C# 代码(C# 语义更接近底层 IL 代码,因此这是可视化所发生情况的好方法):
public class Test : IDisposable
{
public Test()
{
Console.WriteLine("ctor");
}
private void ~Test()
{
Console.WriteLine("dtor");
}
public static void Foo()
{
new Test().Dispose();
}
protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool A_0)
{
if (A_0)
{
this.~Test();
}
else
{
this.Finalize();
}
}
public virtual void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize((object)this);
}
}
可以看到 dispose 模式是编译器自动实现的。
~Test“析构函数”编译为私有方法,并为您生成IDisposable::Dispose的实现。出于某种原因,编译器还会调用(空)终结器。
此外,正如您在静态 Foo 方法中看到的,foo->~Test(); 被简单地转换为对 Dispose 的调用。编译器不会让你直接调用foo->Dispose();。
但是标准调用“析构函数”的方法(以及 Dispose 方法)是使用 delete 关键字:delete foo; 与 C++ 中的 foo->~Test(); 相同/CLI 当foo 是托管句柄时。
注意,在这个例子中,不要写:
auto foo = gcnew CppCli::Test();
foo->Whatever();
delete foo;
您可以使用堆栈语义并编写:
Test foo;
foo.Whatever();
foo.~Test(); 将在foo 超出范围时被调用,就像在常规 C++ 中一样。
为了完整起见,以下是整个事物与终结器交互的方式。让我们添加一个:
public ref class Test
{
public:
Test() { System::Console::WriteLine("ctor"); }
~Test() { System::Console::WriteLine("dtor"); }
!Test() { System::Console::WriteLine("finalizer"); }
};
这将反编译为以下类似 C# 的代码:
public class Test : IDisposable
{
public Test()
{
Console.WriteLine("ctor");
}
// This is the real finalizer
~Test()
{
this.Dispose(false);
}
// This is what C++/CLI compiles ~Test to
// Let's call this MethodA
private void ~Test()
{
Console.WriteLine("dtor");
}
// This is what C++/CLI compiles !Test to
// Let's call this MethodB
private void !Test()
{
Console.WriteLine("finalizer");
}
[HandleProcessCorruptedStateExceptions]
protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool A_0)
{
if (A_0)
{
this.~Test(); // MethodA, NOT the finalizer
}
else
{
try
{
this.!Test(); // MethodB
}
finally
{
base.Finalize();
}
}
}
public virtual void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize((object)this);
}
}
请注意,为了增加混淆,在 C# 中,终结器是 ~Test(),这与 C++/CLI 编译器为您的析构函数生成的 private void ~Test() 函数不同。