问题
This question already has an answer here:
- Cleanest way to write retry logic? 27 answers
Is there a better way to write this code without using goto
? It seems awkward, but I can't think of a better way. I need to be able to perform one retry attempt, but I don't want to duplicate any code.
public void Write(string body)
{
bool retry = false;
RetryPoint:
try
{
m_Outputfile.Write(body);
m_Outputfile.Flush();
}
catch (Exception)
{
if( retry )
throw;
// try to re-open the file...
m_Outputfile = new StreamWriter(m_Filepath, true);
retry = true;
goto RetryPoint;
}
}
回答1:
Here is the basic logic that I would use instead of a goto statement:
bool succeeded = false;
int tries = 2;
do
{
try
{
m_Outputfile = new StreamWriter(m_Filepath, true);
m_Outputfile.Write(body);
m_Outputfile.Flush();
succeeded = true;
}
catch(Exception)
{
tries--;
}
}
while (!succeeded && tries > 0);
I just added # of tries logic, even though the original question didn't have any.
回答2:
Michael's solution doesn't quite fulfill the requirements, which are to retry a fixed number of times, throwing the last failure.
For this, I would recommend a simple for loop, counting down. If you succeed, exit with break (or, if convenient, return). Otherwise, let the catch check to see if the index is down to 0. If so, rethrow instead of logging or ignoring.
public void Write(string body, bool retryOnError)
{
for (int tries = MaxRetries; tries >= 0; tries--)
{
try
{
_outputfile.Write(body);
_outputfile.Flush();
break;
}
catch (Exception)
{
if (tries == 0)
throw;
_outputfile.Close();
_outputfile = new StreamWriter(_filepath, true);
}
}
}
In the example above, a return would have been fine, but I wanted to show the general case.
回答3:
@Michael's answer (with a correctly implemented out catch block) is probably the easiest to use in your case, and is the simplest. But in the interest of presenting alternatives, here is a version that factors the "retry" flow control into a separate method:
// define a flow control method that performs an action, with an optional retry
public static void WithRetry( Action action, Action recovery )
{
try {
action();
}
catch (Exception) {
recovery();
action();
}
}
public void Send(string body)
{
WithRetry(() =>
// action logic:
{
m_Outputfile.Write(body);
m_Outputfile.Flush();
},
// retry logic:
() =>
{
m_Outputfile = new StreamWriter(m_Filepath, true);
});
}
You could, of course, improve this with things like retry counts, better error propagation, and so on.
回答4:
What if you put it in a loop? Something similar to this, maybe.
while(tryToOpenFile)
{
try
{
//some code
}
catch
{
}
finally
{
//set tryToOpenFile to false when you need to break
}
}
回答5:
public void Write(string body, bool retryOnError)
{
try
{
m_Outputfile.Write(body);
m_Outputfile.Flush();
}
catch (Exception)
{
if(!retryOnError)
throw;
// try to re-open the file...
m_Outputfile = new StreamWriter(m_Filepath, true);
Write(body, false);
}
}
回答6:
Try something like the following:
int tryCount = 0;
bool succeeded = false;
while(!succeeded && tryCount<2){
tryCount++;
try{
//interesting stuff here that may fail.
succeeded=true;
} catch {
}
}
回答7:
with a boolean
public void Write(string body)
{
bool NotFailedOnce = true;
while (true)
{
try
{
_outputfile.Write(body);
_outputfile.Flush();
return;
}
catch (Exception)
{
NotFailedOnce = !NotFailedOnce;
if (NotFailedOnce)
{
throw;
}
else
{
m_Outputfile = new StreamWriter(m_Filepath, true);
}
}
}
}
来源:https://stackoverflow.com/questions/4148866/better-way-to-write-retry-logic-without-goto