Effective C# Item15:利用using和try/finally语句来清理资源

    在内存资源分配方面,.NET可以分为托管资源和非托管资源两部分。对于托管资源,.NET框架会负责进行垃圾回收的工作;对于非托管的资源,我们需要手动去释放资源。通常情况下,我们使用IDisposable接口中的Dispose()方法释放资源,而调用Dispose()方法的责任,由资源的拥有者或者对象的拥有者执行,即我们这些程序员,确保调用Dispose()方法的最佳方式就是使用using或者try/finally语句块。

    所有拥有非托管资源的类型,都应该实现IDisposable接口,另外作为一种保障措施,这种类型还会创建一个终结器,以防止我们忘记调用Dispose()方法,如果我们忘记了调用Dispose()方法,那么其中的非内存资源会在随后终结器执行时被释放。这样对象在内存中存留的时间会比较长,应用程序对资源的清理也比较慢。

    我们可以使用using的方式来强制调用Dispose()方法,查看以下代码。

代码
1 public void ExecuteCommand( string connString,
2 string commandString )
3 {
4 using ( SqlConnection myConnection = new
5 SqlConnection( connString ))
6 {
7 using ( SqlCommand mySqlCommand = new
8 SqlCommand( commandString,
9 myConnection ))
10 {
11 myConnection.Open();
12 mySqlCommand.ExecuteNonQuery();
13 }
14 }
15 }
    上述代码中,SqlConnection和SqlCommand是两个需要释放资源的地方,其中在变量声明时,使用了using,它的作用和以下的代码相同。

代码
1 SqlConnection myConnection = null;
2
3 // Example Using clause:
4 using ( myConnection = new SqlConnection( connString ))
5 {
6 myConnection.Open();
7 }
8
9 // example Try / Catch block:
10 try {
11 myConnection = new SqlConnection( connString );
12 myConnection.Open();
13 }
14 finally {
15 myConnection.Dispose( );
16 }
    注意,如果我们对一个没有实现IDisposable接口的对象使用using语句,那么C#编译器会产生错误,只有当编译时类型实现了IDisposable接口时,using语句才会正常编译。

    我们可以使用as进行类型转换,以防止出现编译错误。

1 object obj = Factory.CreateResource( );
2 using ( obj as IDisposable )
3 Console.WriteLine( obj.ToString( ));
    上述代码中,如果obj没有实现IDisposable接口,那么变为using(null),这种做法很安全,不会产生变异错误,只是不会做任何事情。

    在释放某些对象的资源时,我们会发现有些类型既支持Dispose()方法,也支持Close()方法,例如SqlConnection类型,我们也可以通过调用Close()方法来释放资源。

    Dispose()方法和Close()方法的区别:Dispose()方法除了释放资源之外,还会通知垃圾收集器对该对象不再需要执行终结操作,它是通过调用GC.SuppressFinalize()方法来实现的;Close()方法一般不会这么处理,因此在调用了Close()方法的对象,依然会停留在终结队列中。因此,我们应该优先调用Dispose()方法。

    Dispose()方法不会将对象从内存上删除,它只是让对象释放非托管资源,这意味着如果释放的是仍被使用的对象,那么可能会遇到一些问题,因此,我们不应该释放那些仍然被程序其他地方引用的对象。

posted @ 2010-01-13 22:03  李潘  阅读(581)  评论(0编辑  收藏  举报