2017-02-16 40 views
1

在浏览与通过SMTP发送电子邮件相关的一些代码时,我在MSDN中收到了以下代码片断。为什么破坏在这里被明确地调用?

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(); 
} 

我只是想知道他们为什么在这里调用析构函数?我在这里错过了什么吗?

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

回答

2

在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编译器为您的析构函数生成。

+0

非常感谢您的详细解释,真的很有帮助。 – Geek

+1

你也许应该注意''Test()'语法不是标准的。处理托管对象的规范方式是使用'delete',与C++对象一样。 –

+0

@DavidYaw oops,你是对的,这是一个重要的观点,谢谢! –

相关问题