正确实现 IDisposable 接口2
点击次数:25 次 发布日期:2008-11-26 11:36:17 作者:源代码网
|
源代码网推荐 源代码网推荐 1 public ref class Foo 源代码网推荐 2 { 源代码网推荐 3 public: 源代码网推荐 4 Foo(); 源代码网推荐 5 ~Foo(); // destructor 源代码网推荐 6 !Foo(); // finalizer 源代码网推荐 7 }; 源代码网推荐 8 源代码网推荐 源代码网推荐 源代码网推荐 “!”函数(我实在不知道应该怎么称呼它)取代原来Managed C++中的Finalize()被GC调用。MSDN建议,为了减少代码的重复,可以写这样的代码: 源代码网推荐 源代码网推荐 1 ~Foo() 源代码网推荐 2 { 源代码网推荐 3 //释放托管的资源 源代码网推荐 4 this->!Foo(); 源代码网推荐 5 } 源代码网推荐 6 源代码网推荐 7 !Foo() 源代码网推荐 8 { 源代码网推荐 9 //释放非托管的资源 源代码网推荐 10 } 源代码网推荐 11 源代码网推荐 源代码网推荐 源代码网推荐 对于上面这个类,实际上C++/CLI生成对应的C#代码是这样的: 源代码网推荐 源代码网推荐 源代码网推荐 源代码网推荐 源代码网推荐 1 public class Foo 源代码网推荐 2 { 源代码网推荐 3 private void !Foo() 源代码网推荐 4 { 源代码网推荐 5 // 释放非托管的资源 源代码网推荐 6 } 源代码网推荐 7 源代码网推荐 8 private void ~Foo() 源代码网推荐 9 { 源代码网推荐 10 // 释放托管的资源 源代码网推荐 11 !Foo(); 源代码网推荐 12 } 源代码网推荐 13 源代码网推荐 14 public Foo() 源代码网推荐 15 { 源代码网推荐 16 } 源代码网推荐 17 源代码网推荐 18 public void Dispose() 源代码网推荐 19 { 源代码网推荐 20 Dispose(true); 源代码网推荐 21 GC.SuppressFinalize(this); 源代码网推荐 22 } 源代码网推荐 23 源代码网推荐 24 protected virtual void Dispose(bool disposing) 源代码网推荐 25 { 源代码网推荐 26 if (disposing) 源代码网推荐 27 { 源代码网推荐 28 ~Foo(); 源代码网推荐 29 } 源代码网推荐 30 else 源代码网推荐 31 { 源代码网推荐 32 try 源代码网推荐 33 { 源代码网推荐 34 !Foo(); 源代码网推荐 35 } 源代码网推荐 36 finally 源代码网推荐 37 { 源代码网推荐 38 base.Finalize(); 源代码网推荐 39 } 源代码网推荐 40 } 源代码网推荐 41 } 源代码网推荐 42 源代码网推荐 43 protected void Finalize() 源代码网推荐 44 { 源代码网推荐 45 Dispose(false); 源代码网推荐 46 } 源代码网推荐 47 } 源代码网推荐 48 源代码网推荐 源代码网推荐 源代码网推荐 由于~Foo()和!Foo()不会被重复调用(至少MS这样认为),因此在这段代码中没有和前面m_disposed相同的变量,但是基本的结构是一样的。 源代码网推荐 源代码网推荐 源代码网推荐 源代码网推荐 并且,可以看到实际上并不是~Foo()和!Foo()就是Dispose和Finalize,而是C++/CLI编译器生成了两个Dispose和Finalize函数,并在合适的时候调用它们。C++/CLI其实已经做了很多工作,但是唯一的一个问题就是依赖于用户在~Foo()中调用!Foo()。 源代码网推荐 源代码网推荐 源代码网推荐 源代码网推荐 关于资源释放,最后一点需要提的是Close函数。在语义上它和Dispose很类似,按照MSDN的说法,提供这个函数是为了让用户感觉舒服一点,因为对于某些对象,例如文件,用户更加习惯调用Close()。 源代码网推荐 源代码网推荐 源代码网推荐 源代码网推荐 然而,毕竟这两个函数做的是同一件事情,因此MSDN建议的代码就是: 源代码网推荐 源代码网推荐 源代码网推荐 源代码网推荐 1 public void Close() 源代码网推荐 2 { 源代码网推荐 3 Dispose((); 源代码网推荐 4 } 源代码网推荐 5 源代码网推荐 6 源代码网推荐 这里直接调用不带参数的Dispose函数以获得和Dispose相同的语义。这样似乎就圆满了,但是从另外一方面说,如果同时提供了Dispose和Close,会给用户带来一些困惑。没有看到代码细节的前提下,很难知道这两个函数到底有什么区别。因此在.NET的代码设计规范中说,这两个函数实际上只能让用户用一个。因此建议的模式是: 源代码网推荐 源代码网推荐 1 public class Foo: IDisposable 源代码网推荐 2 { 源代码网推荐 3 public void Close() 源代码网推荐 4 { 源代码网推荐 5 Dispose(); 源代码网推荐 6 } 源代码网推荐 7 源代码网推荐 8 void IDisposable.Dispose() 源代码网推荐 9 { 源代码网推荐 10 Dispose(true); 源代码网推荐 11 GC.SuppressFinalize(this); 源代码网推荐 12 } 源代码网推荐 13 源代码网推荐 14 protected virtual void Dispose(bool disposing) 源代码网推荐 15 { 源代码网推荐 16 // 同前 源代码网推荐 17 } 源代码网推荐 18 } 源代码网推荐 19 源代码网推荐 源代码网推荐 源代码网推荐 这里使用了一个所谓的接口显式实现:void IDisposable.Dispose()。这个显式实现只能通过接口来访问,但是不能通过实现类来访问。因此: 源代码网推荐 源代码网推荐 源代码网推荐 1 Foo foo = new Foo(); 源代码网推荐 2 源代码网推荐 3 foo.Dispose(); // 错误 源代码网推荐 4 (foo as IDisposable).Dispose(); // 正确 源代码网推荐 5 源代码网推荐 源代码网推荐 源代码网推荐 这样做到了兼顾两者。对于喜欢使用Close的人,可以直接用 foo.Close(),并且他看不到 Dispose()。对于喜欢Dispose的,他可以把类型转换为 IDisposable 来调用,或者使用using语句。两者皆大欢喜! 源代码网推荐 http://www.cnblogs.com/xlshcn/archive/2007/01/16/idisposable.html 源代码网推荐 做人要厚道,请注明转自酷网动力(www.ASPCOOL.COM)。 源代码网推荐 源代码网供稿. |
