这是一个揭示我缺乏经验的问题:我有一个方法 DoSomething(),如果它不能干净地执行它就会引发异常。如果失败了,我会多次尝试不太准确的方法 DoSomethingApproximately(),希望能找到一个足够好的解决方案;如果这也失败了我终于打电话给 DoSomethingInaccurateButGuaranteedToWork()。这三个都是属于这个对象的方法。
两个问题:首先,这个(难以置信的丑陋)模式是否可以接受,还是有更优雅的方式?
其次,考虑到它可能引发异常,最好的方法是跟踪我多少次调用 DoSomethingApproximately()?我目前在对象中保留一个变量iNoOfAttempts,并嵌套试块......这太可怕了,我很惭愧。
答案 0 :(得分:4)
您不应该对应用程序的控制流使用异常。
在你的情况下,我将这三个方法组合成一个单一的方法,让它返回哪个特定的方法成功,可能有一个枚举或类似的东西。
答案 1 :(得分:2)
返回错误代码而不是抛出异常。
如果这些方法失败的方式会抛出异常,请在同一方法中捕获所有异常并采取适当的操作,例如增加计数器并返回错误代码。
bool result = DoSomething();
while (!result && tries < MAX_TRIES) {
result = DoSomethingApproximately(); //This will increment tries
if (tries > THRESHOLD) {
result = DoSomethingThatAlwaysWorks();
}
}
答案 2 :(得分:2)
(伪代码)怎么样:
try{ return doSomething(); }
catch(ExpectedException) { ...not much here probably...}
for(i = 0 to RETRIES){
try{ return doSomethingApproximately; }
catch(ExpectedException) { ...not much here probably...}
}
doSomethingGuaranteed();
附录:
我强烈建议您不要使用特殊的返回值,因为这意味着函数的每个用户都必须知道某些返回值是特殊的。根据功能的范围,返回可以正常处理的范围的普通部分可能是明智的,例如,一个空的集合。当然,这可能使得无法区分失败,而“正确”的答案是空集合(在本例中)。
答案 3 :(得分:2)
在结构路径中转到整个函数指针。只是为了加强它,我会使用一个队列和一些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;
}
});