在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,你是對的,這是一個重要的觀點,謝謝! –