建议69:应使用finally避免资源泄漏
除非发生让应用程序中断的异常,否则finally总是会先于return执行。finally的这个语言特性决定了资源释放的最佳位置就是在finally块中;另外,资源释放会随着调用堆栈由下往上执行。下面的代码验证了这一点,先定义一个需要释放的类:
class ClassShouldDisposeBase : IDisposable { string _methodName; public ClassShouldDisposeBase(string methodName) { _methodName = methodName; } public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); Console.WriteLine("在方法:" + _methodName + "中被释放!"); } protected virtual void Dispose(bool disposing) { if (disposing) { //执行基本的清理代码 } } ~ClassShouldDisposeBase() { this.Dispose(false); } }
再来模拟一个调用堆栈:
static void Main(string[] args) { Method1(); } static void Method1() { ClassShouldDisposeBase c = null; try { c = new ClassShouldDisposeBase("Method1"); Method2(); } finally { c.Dispose(); } } static void Method2() { ClassShouldDisposeBase c = null; try { c = new ClassShouldDisposeBase("Method2"); } finally { c.Dispose(); } }
输出:
在方法:Method2中被释放!
在方法:Method1中被释放!
finally不会因为调用堆栈中存在的异常而被终止,CLR会先执行catch块,然后再执行finally块。如下:
static void Main(string[] args) { Method3(); } static void Method3() { ClassShouldDisposeBase c = null; try { c = new ClassShouldDisposeBase("Method3"); Method4(); } catch { Console.WriteLine("在Method3中捕获了异常。"); } finally { c.Dispose(); } } static void Method4() { ClassShouldDisposeBase c = null; try { c = new ClassShouldDisposeBase("Method4"); throw new Exception(); } catch { Console.WriteLine("在Method4中捕获了异常。"); throw; } finally { c.Dispose(); } }
输出:
在Method4中捕获了异常。
在方法:Method4中被释放!
在Method3中捕获了异常。
在方法:Method3中被释放!
转自:《编写高质量代码改善C#程序的157个建议》陆敏技