2017-02-16 2 views
1

SMTP経由で電子メールを送信することに関連するコードをブラウズしているうちに、私はMSDNで次のスニペットを取得しました。destructがここで明示的に呼び出されているのはなぜですか?

static void CreateMessageWithAttachment(String^ server) 
{ 
    String^ file = L"data.xls"; 

    MailMessage^ message = gcnew MailMessage(L"[email protected]",L"[email protected]",L"Quarterly data report.",L"See the attached spreadsheet."); 

    Attachment^ data = gcnew Attachment(file, MediaTypeNames::Application::Octet); 

    ContentDisposition^ disposition = data->ContentDisposition; 
    disposition->CreationDate = System::IO::File::GetCreationTime(file); 
    disposition->ModificationDate = System::IO::File::GetLastWriteTime(file); 
    disposition->ReadDate = System::IO::File::GetLastAccessTime(file); 

    message->Attachments->Add(data); 

    SmtpClient^ client = gcnew SmtpClient(server); 

    client->Credentials = CredentialCache::DefaultNetworkCredentials; 
    client->Send(message); 

    data->~Attachment(); 
    client->~SmtpClient(); 
} 

ここでデストラクタを呼び出すのはなぜでしょうか?私はここに何かを逃している? C++/CLIで

答えて

2
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コンパイラがデストラクタ用に生成する関数です。

+0

詳細な説明をいただきありがとうございます。本当に参考になりました。 – Geek

+1

'〜Test()'の構文は標準ではないことに気付くべきでしょう。管理対象オブジェクトを処理する標準的な方法は、C++オブジェクトと同じように 'delete'を使うことです。 –

+0

@DavidYawおっと、そうです、それは重要なポイントです、ありがとう! –

関連する問題