引发异常时尝试不同方法的模式
时间:2020-03-06 14:39:30 来源:igfitidea点击:
这是一个暴露我缺乏经验的问题:我有一个方法DoSomething(),如果它不能做到干净整洁,则会抛出异常。如果失败,我会尝试几次不太准确的方法DoSomethingroxly(),以期找到足够好的解决方案。如果仍然失败,我最终将调用DoSomethingInaccurateButGuaranteedToWork()。这三个都是属于该对象的方法。
两个问题:首先,这种(公认的丑陋)模式是可以接受的,还是有一种更优雅的方式?
其次,鉴于它可能会引发异常,因此最好的方法来跟踪我调用了DoSomethingroxly()的次数?我目前在对象中保留变量iNoOfAttempts,并嵌套try块...这太可怕了,我感到羞愧。
解决方案
返回错误代码,而不是引发异常。
如果这些方法失败的方式确实引发了异常,请在同一方法中将它们全部捕获并采取适当的措施,例如增加计数器并返回错误代码。
bool result = DoSomething(); while (!result && tries < MAX_TRIES) { result = DoSomethingApproximately(); //This will increment tries if (tries > THRESHOLD) { result = DoSomethingThatAlwaysWorks(); } }
我们绝对不应将异常用于应用程序的控制流。
在情况下,我将这三种方法组合在一起成为一个方法,并让它返回成功的特定方法,也许使用枚举或者类似方法。
怎么样(伪代码):
try{ return doSomething(); } catch(ExpectedException) { ...not much here probably...} for(i = 0 to RETRIES){ try{ return doSomethingApproximately; } catch(ExpectedException) { ...not much here probably...} } doSomethingGuaranteed();
附录:
我强烈建议我们不要使用特殊的返回值,因为这意味着该函数的每个用户都必须知道某些返回值是特殊的。取决于函数的范围,明智的是返回可以正常处理的范围的普通部分,例如一个空集合。当然,这可能使得无法区分失败和"正确"答案是空集合(在此示例中)。
在结构路径中遍历整个函数指针。只是为了增加趣味性,我将使用一个Queue和一些LINQ。
Queue<Action> actions = new Queue<Action>(new Action[] { obj.DoSomething, obj.DoSomethingApproximately, obj.DoSomethingApproximately, obj.DoSomethingApproximately, obj.DoSomethingApproximately, obj.DoSomethingGuaranteed }); actions.First(a => { try { a(); return true; } catch (Exception) { return false; } });