Here's a question to expose my lack of experience: I have a method DoSomething() which throws an exception if it doesn't manage to do it cleanly. If it fails, I try the less accurate method DoSomethingApproximately() several times in the hope that it will find a sufficiently good solution; if this also fails I finally call DoSomethingInaccurateButGuaranteedToWork(). All three are methods belonging to this object.
这是一个暴露我缺乏经验的问题:我有一个方法DoSomething(),如果它不能干净地完成它就抛出异常。如果它失败了,我会多次尝试不太准确的方法DoSomethingApproximately(),希望它能找到一个足够好的解决方案;如果这也失败了我最后调用DoSomethingInaccurateButGuaranteedToWork()。这三个都是属于这个对象的方法。
Two questions: first, is this (admittedly ugly) pattern acceptable, or is there a more elegant way?
两个问题:首先,这个(公认的丑陋)模式是否可以接受,还是有更优雅的方式?
Second, what is the best way to keep track of how many times I have called DoSomethingApproximately(), given that it is likely to throw an exception? I am currently keeping a variable iNoOfAttempts in the object, and nesting try blocks... this is horrible and I am ashamed.
其次,考虑到它可能引发异常,跟踪我调用DoSomethingApproximately()的次数的最佳方法是什么?我目前在对象中保留一个变量iNoOfAttempts,并嵌套试块......这太可怕了,我很惭愧。
4 个解决方案
#1
4
You should never use exceptions for control flow of your application.
您永远不应该对应用程序的控制流使用异常。
In your case I'd bunch the three methods together into a single method and have it return which particular approach succeeded, maybe with an enum or something like that.
在你的情况下,我将这三个方法组合在一起成为一个方法,让它返回哪个特定的方法成功,可能有一个枚举或类似的东西。
#2
2
Return an error code instead of throwing an exception.
返回错误代码而不是抛出异常。
If the ways those methods fail do throw exceptions, catch them all in the same method and take appropriate action, like increasing a counter and returning an error code.
如果这些方法失败的方式会抛出异常,则在同一方法中捕获所有异常并采取适当的操作,例如增加计数器并返回错误代码。
bool result = DoSomething();
while (!result && tries < MAX_TRIES) {
result = DoSomethingApproximately(); //This will increment tries
if (tries > THRESHOLD) {
result = DoSomethingThatAlwaysWorks();
}
}
#3
2
Go the whole function pointers in a structure route. Just to spice it up, I'll use a Queue and some LINQ.
在结构路径中转到整个函数指针。只是为了加强它,我会使用一个队列和一些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;
}
});
#4
2
How about (pseudocode):
怎么样(伪代码):
try{ return doSomething(); }
catch(ExpectedException) { ...not much here probably...}
for(i = 0 to RETRIES){
try{ return doSomethingApproximately; }
catch(ExpectedException) { ...not much here probably...}
}
doSomethingGuaranteed();
Addendum:
I strongly recommend that you do not use special return values, because that means that every single user of the function has to know that some of the return values are special. Depending on the range of the function, it may be sensible to return an ordinary part of the range that can be dealt with normally, e.g. an empty collection. Of course, that may make it impossible to distinguish between failure, and the "right" answer being the empty collection (in this example).
我强烈建议您不要使用特殊的返回值,因为这意味着函数的每个用户都必须知道某些返回值是特殊的。根据功能的范围,返回可以正常处理的范围的普通部分可能是明智的,例如,一个空的集合。当然,这可能使得无法区分失败,并且“正确”答案是空集合(在该示例中)。
#1
4
You should never use exceptions for control flow of your application.
您永远不应该对应用程序的控制流使用异常。
In your case I'd bunch the three methods together into a single method and have it return which particular approach succeeded, maybe with an enum or something like that.
在你的情况下,我将这三个方法组合在一起成为一个方法,让它返回哪个特定的方法成功,可能有一个枚举或类似的东西。
#2
2
Return an error code instead of throwing an exception.
返回错误代码而不是抛出异常。
If the ways those methods fail do throw exceptions, catch them all in the same method and take appropriate action, like increasing a counter and returning an error code.
如果这些方法失败的方式会抛出异常,则在同一方法中捕获所有异常并采取适当的操作,例如增加计数器并返回错误代码。
bool result = DoSomething();
while (!result && tries < MAX_TRIES) {
result = DoSomethingApproximately(); //This will increment tries
if (tries > THRESHOLD) {
result = DoSomethingThatAlwaysWorks();
}
}
#3
2
Go the whole function pointers in a structure route. Just to spice it up, I'll use a Queue and some LINQ.
在结构路径中转到整个函数指针。只是为了加强它,我会使用一个队列和一些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;
}
});
#4
2
How about (pseudocode):
怎么样(伪代码):
try{ return doSomething(); }
catch(ExpectedException) { ...not much here probably...}
for(i = 0 to RETRIES){
try{ return doSomethingApproximately; }
catch(ExpectedException) { ...not much here probably...}
}
doSomethingGuaranteed();
Addendum:
I strongly recommend that you do not use special return values, because that means that every single user of the function has to know that some of the return values are special. Depending on the range of the function, it may be sensible to return an ordinary part of the range that can be dealt with normally, e.g. an empty collection. Of course, that may make it impossible to distinguish between failure, and the "right" answer being the empty collection (in this example).
我强烈建议您不要使用特殊的返回值,因为这意味着函数的每个用户都必须知道某些返回值是特殊的。根据功能的范围,返回可以正常处理的范围的普通部分可能是明智的,例如,一个空的集合。当然,这可能使得无法区分失败,并且“正确”答案是空集合(在该示例中)。