在浏览与通过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();
答案 0 :(得分: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;
是相同的当foo->~Test();
是托管句柄时,在C ++ / CLI中为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()
,它与C ++ / CLI编译器为析构函数生成的private void ~Test()
函数不同。