最近偶正在关注 C++/CLI ,经常听人在介绍 自动确定性资源回收(Automatic deterministic destruction) 特性的时候,宣称 C# 的 using statement 不能在一行中初始化多个变量,进而说明 C++/CLI 的这一设计多么优秀。虽然后果不是很严重,偶也不是很生气,但是为了开始在 cnblogs 的第一篇文章,我决心要为 C# using statement 平反昭雪!
![emcry.gif](/Emoticons/emcry.gif)
using( ADisposableClass foo = new ADisposableClass() )
{
... ...
}
这样在代码被编译成 MSIL 的过程中 C# 编译器会自动生成一个.try / finally 块,并在 finally 中调用 foo.Dispose() 方法,以保证资源的释放。但是人们还是要确保 ADisposableClass 实现了 IDisposable 接口。
经过: Stanley Lippman 认为这样很累,所以他在 C++/CLI 中引入了自动确定性资源回收。其本质是把引用类型的析构函数(确定性析构)自动映射为 Dispose() 方法;添加了一种称为 非确定析构函数 的东东,并把它映射成 Finalize() 方法。
ref class ADisposableClass
{
public:
~ADisposableClass () // map to Dispose()
{
// Do release your resource here
}
!ADisposableClass (){} // map to Finalize()
}
如果我们在某个地方写了这么一行:
ADisposableClass foo(); // 注意这是一个初始化栈变量的语法,但是实际上 foo 还是分配于托管堆中(至少目前如此)。
那么在离开当前作用域之前,foo 会被自动析构。原因是编译器自动插入了一个 .try / fault 块,原理和 using statement 没有任何差别。
结果:我们获得了一种以简洁语法自动管理重要资源的方式。其优势在于我们不必显式实现 IDisposable;不必显式指定作用域;从逻辑上理顺了(确定性)析构函数和Finalize()方法的差别。但是采用栈变量语法初始化的引用变量似乎会造成一些问题,具体请参见 http://blog.joycode.com/lijianzhong/archive/2005/01/10/42762.aspx
解读2:C# 的 using statement 不能 在一行中初始化多个变量? 起因:有人认为如果在同一个作用域中需要使用很多包含非托管资源的对象,C# 就一定要使用嵌套的 using statement。
using( A a = new A(...) )
{
using( B b = new B(...) )
{
using( C c = new c(...) )
{
... ...
}
}
}
而 C++/CLI 只要这样写:
A a(...);
B b(...);
C c(...);
经过:偶认为 C++/CLI 的语法在这一点上固然简洁到了家。不过 C# 的写法也不见得一定要这么丑陋。既然大家都实现了IDisposable。我们何必嵌套那么多层呢
![emsmileo.gif](/Emoticons/emsmileo.gif)
using( IDisposable a = new A(...), b = new B(...), c = new C(...) )
{
(a as A) ... ...
(b as B) ... ...
(c as C) ... ...
}
结果:虽然表面上的写法有那么一些差别,但是编译成 MSIL 之后,无论是C# using statement、还是 C++/CLI 自动确定性资源回收 甚至 是你自己写的嵌套 try / finally 块,生成的代码都是相差无几的。统统都是 .Try / Finally (Fault) 块的嵌套。所以偶感觉 C++/CLI 的这项特性基本只是个语法层面的小hack,没有什么好拿来当卖点的样子。IMHO,STL.net 才更像是值得人们期待的东东。