前言
这里主要说一个使用using躲过异常的小技巧。
我原来就遇到过类似的问题好几次了,也没想到办法,直接有一天,调试得实在受不了了,才认真想了以下的解决方案。
问题
原来的代码是这样的:
public abstract class Command : RoutedUICommand { private bool _isExecuting = false; public void Execute(CommandContext commandContext) { this._isExecuting = true; try { OnExecute(commandContext); } catch { throw; } finally { this._isExecuting = false; } } protected abstract void OnExecute(CommandContext commandContext); }
这是一个抽象的命令类,这里只贴出了这个问题的主要的逻辑:需要在OnExecute方法执行之前设置_isExecuting的值为true,然后执行OnExecute方法,然后不管是否出现异常,都在执行完毕后,设置为false。子类实现这个类实现OnExecute方法来编写自己真正的执行代码。这时比较麻烦的一个问题是:在代码编写阶段,当子类的OnExecute方法内部出现异常时,Visual Studio都会直接把错误给定在这个类上,如下:
子类:
private class ConcreteCommand : Command { protected override void OnExecute(CommandContext commandContext) { int i = 0; int j = 100 / i; //....... } }
出现异常:
调试的过程中,无法直接定位到子类,当代码很多时,找实现这个基类的子类是很烦人的事。而且找到了它以后,打上断点,还得重新运行一遍来运行同样的bug路径。时间就是这样浪费的,调试得很崩溃……
解决
需要重构了基类的代码,但是由于Execute方法的设置_isExecuting字段的逻辑不能改变,所以并不简单。灵光一闪,有了以下的实现:
public abstract class Command { public void Execute(CommandContext commandContext) { this._isExecuting = true; using (this.__isExecuting) { OnExecute(commandContext); } } protected abstract void OnExecute(CommandContext commandContext); private bool _isExecuting { get { return this.__isExecuting.Value; } set { this.__isExecuting.Value = value; } } private IsExecutingWrapper __isExecuting = new IsExecutingWrapper(); /// <summary> /// 原来的模式增加了调试的困难度。 /// 添加这个方法方便调试。 /// </summary> private class IsExecutingWrapper : IDisposable { private bool _value; public bool Value { get { return this._value; } set { this._value = value; } } #region IDisposable Members public void Dispose() { this._value = false; } #endregion } }
后话
因为我不只一次遇到过这个问题,所以我猜测肯定还会有朋友会遇到同样的问题。所以就把这个小问题冒昧的发在了首页。希望和大家分享。另外,如果你有更好的方法,可以用力的拍我。 :)