为什么要在此处明确调用 destruct?

Why destruct is being called here explicitly?

在浏览一些与通过 SMTP 发送电子邮件相关的代码时,我在 MSDN 中得到了以下片段。

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

   MailMessage^ message = gcnew MailMessage( L"jane@contoso.com",L"ben@contoso.com",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();

在 C++/CLI 中,ref class 析构函数是对 Dispose pattern.

的抽象

以下 C++/CLI class,编译时:

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

你可以看到dispose模式是由编译器自动实现的。

~Test "destructor" 编译为私有方法,并为您生成 IDisposable::Dispose 的实现。出于某种原因,编译器还调用了(空)终结器。

此外,正如您在静态 Foo 方法中看到的那样,foo->~Test(); 被简单地转换为对 Dispose 的调用。编译器不会让你直接调用 foo->Dispose();

但是调用 "destructor"(因此调用 Dispose 方法)的 标准 方法是使用 delete 关键字:[当 foo 是托管句柄时,=25=] 与 C++/CLI 中的 foo->~Test(); 相同。

注意在这个例子中,不是写:

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(),它与 C++/CLI 编译器的 private void ~Test() 函数不同为你的析构函数生成。