data->~Attachment();
client->~SmtpClient();
、ref
クラスデストラクタはDispose pattern上の抽象化です。
コンパイルし、次のC++/CLIクラス、次のC#コードへ
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#の意味が根本的な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();
に直接電話することはできません。 foo
が管理ハンドルであるときdelete foo;
は、C++/CLIでfoo->~Test();
と同じである:「デストラクタ」(したがってDispose
メソッド)を呼び出すための
しかし標準アプローチはdelete
キーワードを使用することです。
なお、この例では、代わりに書いている:
auto foo = gcnew CppCli::Test();
foo->Whatever();
delete foo;
あなたは、スタックのセマンティクスを使用することができますし、書き込み:
Test foo;
foo.Whatever();
foo.~Test();
がfoo
が正規のように、スコープの外に出たときに呼び出されますC++。
完全性のために、ここではすべてがファイナライザとやりとりする方法を示します。のは、1を追加してみましょう:private void ~Test()
から異なるある追加の混乱のために、C#でファイナライザが~Test()
である、ということ
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);
}
}
注:
public ref class Test
{
public:
Test() { System::Console::WriteLine("ctor"); }
~Test() { System::Console::WriteLine("dtor"); }
!Test() { System::Console::WriteLine("finalizer"); }
};
これは、次のC#ライクなコードを逆コンパイルC++/CLIコンパイラがデストラクタ用に生成する関数です。
詳細な説明をいただきありがとうございます。本当に参考になりました。 – Geek
'〜Test()'の構文は標準ではないことに気付くべきでしょう。管理対象オブジェクトを処理する標準的な方法は、C++オブジェクトと同じように 'delete'を使うことです。 –
@DavidYawおっと、そうです、それは重要なポイントです、ありがとう! –