Wh开发者_JS百科en an exception is thrown, how can I catch it and then continue execution starting from the line that caused the error?
EDIT: Our program communicates with Indesign Server which crashes all the time and throws random COM related errors (these errors have to do with bugs in the Server itself). Indesign Server also takes a very long time to process commands so when it crashes, we want to avoid restarting execution. Instead, we want to continue from the line that caused the exception. Any line in the program can cause an exception. So technically, we cannot use a loop.
When an exception is thrown, how can I catch it and then continue execution starting from the line that caused the error? (Not the next line; retry the line that caused the exception.)
Do not try to do that. You're approaching this problem from the wrong direction.
The problem is that you have an unreliable subsystem. You have a desired policy for dealing with that unreliable subsystem, which is to retry the operation until it succeeds. If that's the case then don't put that logic in the line-of-business code which uses the subsystem. The line-of-business code should be about the business logic, not about the mechanism you choose to deal with the flaky subsystem. Isolate the mechanism to a specific class which makes the unreliable subsystem into a reliable subsystem.
That is, build a proxy class that has the same interface as the unreliable subsystem, and isolate your retry logic into that proxy class. Then the line-of-business code can use the proxy class as a reliable subsystem.
That said, a policy of "retry it until it works" is possibly a bad policy. If the subsystem is genuinely broken and not just flaky in some transient way, then "retry until it works" means "wait forever", and most users do not like waiting forever. For example, if the exception is a result of a router being unplugged rather than some transient condition then sitting there in a loop until someone plugs the router back in seems like a bad idea.
If you're looking for something general purpose then using a lambda would do the trick. For example
public static class Exception {
public static void Continue(Action action) {
try {
action();
} catch {
// Log
}
}
}
Exception.Continue(() => Statement1());
Exception.Continue(() => Statement2());
I wouldn't consider this an ideal solution though for large scale use. It causes an extra delegate allocation, delegate invocation and method invocation for every statement you use this on. Instead I would focus on identifying the functions which are causing you problems and add explicit wrappers for them individually.
You would have to surround any line that could throw an exception in its own try
/catch
block to accomplish that.
So instead of
try
{
StatementOne(); // Exception thrown here
StatementTwo();
}
catch (SOneException) { ... }
You would have to do:
try
{
StatementOne();
}
catch (SOneException) { ... }
StatementTwo();
If you need to retry an operation due to a (hopefully transient) exception, you can have a method like this:
public static class ExceptionHelper
{
public static void TryNTimesAndThenThrow(Action statement, int retryCount)
{
bool keepTrying = false;
do
{
try
{
statement();
keepTrying = false;
}
catch (Exception)
{
if (retryCount > 0)
{
keepTrying = true;
retryCount--;
}
else
{
// If it doesn't work here, assume it's broken and rethrow
throw;
}
}
} while (keepTrying)
}
}
Then you can just write:
ExceptionHelper.TryNTimesAndThenThrow(() => MightThrowATransientException(), 3);
Keep in mind both methods should be used sparingly. The former will clutter your code quite a bit, while the latter could end up taking a lot more time than you think (since its often a better idea to simply alert the user if something unexpected occurs. Thus the emphasis on a transient exception that you really do expect will disappear if you just try again.)
You could do something like this:
//Retry logic on opening the connection
int retries = 0;
openconnection:
try
{
connection.Open();
}
catch
{
retries++;
//Wait 2 seconds
System.Threading.Thread.Sleep(2000);
if (retries < MAXRETRIES)
{
goto openconnection;
}
else
{
throw;
}
}
I do not know about c#, but this is a javascript that can make a script run multiple times if there is an error.
try {
for (var i=0; (i < t && condition) || i === 0; i++) {
//t is how many times you want the code to run.
//condition should be true when there is an error.
//The code you want to execute multiple times if it fails.
}
} catch (e) {
//The code you want to execute if the code still runs into an error after being repeated multiple times.
}
For example, the following code simulates the case where you set a variable equal to the response from another server. And, the server responds on the 6th time the script is run.
try {
for (var i = 0; (i < 10 && typeof response === "undefined") || i === 0; i++) {
var response = (i === 5) ? 1 : undefined;
if (typeof response === "undefined") {console.log("ERROR!! #" + i)} else {console.log("Success!! #" + i)};
if (i === 9 && typeof response === "undefined") {throw new Error("Fail to get response from other server")};
}
} catch (e) {
console.log("Error Message: '" + e + "'");
}
You can run the above code to see the effect. The following is when another server never reply.
try {
for (var i = 0; (i < 10 && typeof response === "undefined") || i === 0; i++) {
var response = (i === -1) ? 1 : undefined;
if (typeof response === "undefined") {console.log("ERROR!! #" + i)} else {console.log("Success!! #" + i)};
if (i === 9 && typeof response === "undefined") {throw new Error("Fail to get response from other server")};
}
} catch (e) {
console.log("Error Message: '" + e + "'");
}
You can also make it into a function to use it easily.
function retry(code,times,condition,errorMessage) {
try {
for (var i = 0; (i < times && eval(condition)) || i === 0; i++) {
eval(code);
if (i === times-1 && eval(condition) && typeof errorMessage !== "undefined") {throw new Error(errorMessage)};
}
} catch (e) {
console.log("Error Message: '" + e + "'");
}
}
The first two example using the function.
function retry(code,times,condition,errorMessage) {
try {
for (var i = 0; (i < times && eval(condition)) || i === 0; i++) {
eval(code);
if (eval(condition)) {console.log("ERROR!! #" + i)} else {console.log("Success!! #" + i)};
if (i === times-1 && eval(condition) && typeof errorMessage !== "undefined") {throw new Error(errorMessage)};
}
} catch (e) {
console.log("Error Message: '" + e + "'");
}
}
retry("var response = (i === 5) ? 1 : undefined;",10,"typeof response === 'undefined'","Fail to get response from other server")
retry("var response = (i === -1) ? 1 : undefined;",10,"typeof response === 'undefined'","Fail to get response from other server")
I hope this helps some people.
精彩评论