在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);
}
}
你可以看到配置模式是由编译器自动实现的。
~Test
“析构函数”被编译为私有方法,并且为您生成了一个实现IDisposable::Dispose
。由于某种原因,编译器也会调用(空)终结器。
此外,正如您在静态Foo
方法中所看到的,foo->~Test();
仅被转换为致电Dispose
。编译器不会让你直接调用foo->Dispose();
。
但标准的方法来调用“析构函数”(并因此Dispose
方法)是使用delete
关键字:delete foo;
是相同的C/CLI foo->~Test();
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()
,这是不同从private void ~Test()
函数,C++/CLI编译器为您的析构函数生成。
非常感谢您的详细解释,真的很有帮助。 – Geek
你也许应该注意''Test()'语法不是标准的。处理托管对象的规范方式是使用'delete',与C++对象一样。 –
@DavidYaw oops,你是对的,这是一个重要的观点,谢谢! –