正如其他回答者所指出的,您是正确的,处理代码不同的原因是因为它是C++/CLI。
C++/CLI使用不同的风格来编写清理代码。
C#:Dispose()和~ClassName()(终结器)都调用Dispose(bool)。
所有三种方法都由开发人员编写。
C++/CLI:Dispose()和Finalize()都调用Dispose(bool),它将调用~ClassName()或!ClassName()(析构函数和终结器)。
~ClassName()和!ClassName()都是由开发人员编写的。正如您所指出的,在C#中,~ClassName()被编译为protected override void Finalize(),而在C++/CLI中,它仍然是一个名为“~ClassName”的方法。
Dispose()、Finalize()和Dispose(bool)都是由编译器独立编写的。在此过程中,编译器做了一些您通常不应该做的事情。
为了演示,这里有一个简单的C++/CLI类:
public ref class TestClass
{
~TestClass() { Debug::WriteLine("Disposed"); }
!TestClass() { Debug::WriteLine("Finalized"); }
};
这是反编译器Reflector输出的结果,将其转换为C#语法:
public class TestClass : IDisposable
{
private void !TestClass() { Debug.WriteLine("Finalized"); }
private void ~TestClass() { Debug.WriteLine("Disposed"); }
public sealed override void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
[HandleProcessCorruptedStateExceptions]
protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool disposing)
{
if (disposing)
{
this.~TestClass();
}
else
{
try
{
this.!TestClass();
}
finally
{
base.Finalize();
}
}
}
protected override void Finalize()
{
this.Dispose(false);
}
}
编辑
看起来C++/CLI比C#更好地处理构造函数异常。
我在C++/CLI和C#中编写了测试应用程序,定义了一个Parent类和一个Child类,其中Child类的构造函数抛出异常。两个类都有来自它们的构造函数、dispose方法和finalizer的调试输出。
在C++/CLI中,编译器将子构造函数的内容包装在try/fault块中,并在fault中调用父类的Dispose方法。(我相信当异常被某些其他try/catch块捕获时,fault代码会被执行,而不是在catch或finally块中,在这种情况下,它会在向上移动堆栈之前立即执行。但我可能忽略了一些微妙之处。)在C#中,没有隐式的catch或fault块,因此Parent.Dispose()从未被调用。当GC开始收集对象时,两种语言都会调用子类和父类的finalizers。
这是我在C++/CLI中编译的一个测试应用程序:
public ref class Parent
{
public:
Parent() { Debug::WriteLine("Parent()"); }
~Parent() { Debug::WriteLine("~Parent()"); }
!Parent() { Debug::WriteLine("!Parent()"); }
};
public ref class Child : public Parent
{
public:
Child() { Debug::WriteLine("Child()"); throw gcnew Exception(); }
~Child() { Debug::WriteLine("~Child()"); }
!Child() { Debug::WriteLine("!Child()"); }
};
try
{
Object^ o = gcnew Child();
}
catch(Exception^ e)
{
Debug::WriteLine("Exception Caught");
Debug::WriteLine("GC::Collect()");
GC::Collect();
Debug::WriteLine("GC::WaitForPendingFinalizers()");
GC::WaitForPendingFinalizers();
Debug::WriteLine("GC::Collect()");
GC::Collect();
}
输出:
父类()
子类()
CppCLI-DisposeTest.exe 中出现了一个类型为 'System.Exception' 的首次机会异常
~父类()
捕获到异常
GC::Collect()
GC::WaitForPendingFinalizers()
!子类()
!父类()
GC::Collect()
从 Reflector 输出中可以看出,以下是 C++/CLI 编译器如何编译子类构造函数(反编译成 C# 语法)。
public Child()
{
try
{
Debug.WriteLine("Child()");
throw new Exception();
}
fault
{
base.Dispose(true);
}
}
为了比较,这是C#中相应的程序。
public class Parent : IDisposable
{
public Parent() { Debug.WriteLine("Parent()"); }
public virtual void Dispose() { Debug.WriteLine("Parent.Dispose()"); }
~Parent() { Debug.WriteLine("~Parent()"); }
}
public class Child : Parent
{
public Child() { Debug.WriteLine("Child()"); throw new Exception(); }
public override void Dispose() { Debug.WriteLine("Child.Dispose()"); }
~Child() { Debug.WriteLine("~Child()"); }
}
try
{
Object o = new Child();
}
catch (Exception e)
{
Debug.WriteLine("Exception Caught");
Debug.WriteLine("GC::Collect()");
GC.Collect();
Debug.WriteLine("GC::WaitForPendingFinalizers()");
GC.WaitForPendingFinalizers();
Debug.WriteLine("GC::Collect()");
GC.Collect();
return;
}
以下是 C# 的输出结果:
Parent()
Child()
CSharp-DisposeTest.exe 中发生了类型为 'System.Exception' 的第一次机会异常。
捕获到异常
GC::Collect()
GC::WaitForPendingFinalizers()
~Child()
~Parent()
GC::Collect()