C# 编写重试逻辑而无需转到的更好方法
有没有更好的方法来编写此代码而不使用C# 编写重试逻辑而无需转到的更好方法,c#,.net,goto,C#,.net,Goto,有没有更好的方法来编写此代码而不使用goto?这看起来很尴尬,但我想不出更好的办法了。我需要能够执行一次重试尝试,但我不想复制任何代码 public void Write(string body) { bool retry = false; RetryPoint: try { m_Outputfile.Write(body); m_Outputfile.Flush(); } catch (Exception) {
goto
?这看起来很尴尬,但我想不出更好的办法了。我需要能够执行一次重试尝试,但我不想复制任何代码
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;
}
}
以下是我将使用的基本逻辑,而不是goto语句:
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);
我刚刚添加了#尝试逻辑,即使原来的问题没有任何逻辑。如果你把它放在一个循环中怎么办?也许是类似的
while(tryToOpenFile)
{
try
{
//some code
}
catch
{
}
finally
{
//set tryToOpenFile to false when you need to break
}
}
请尝试以下操作:
int tryCount = 0;
bool succeeded = false;
while(!succeeded && tryCount<2){
tryCount++;
try{
//interesting stuff here that may fail.
succeeded=true;
} catch {
}
}
int tryCount=0;
布尔成功=假;
而(!succeed&&tryCountMichael的解决方案并不完全满足要求,即重试固定次数,抛出最后一次失败
为此,我建议使用一个简单的For循环,倒计时。如果成功,请使用break退出(或者,如果方便,使用return)。否则,让catch检查索引是否降到0。如果是,请重新刷新,而不是记录或忽略
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);
}
}
}
在上面的示例中,返回是可以的,但我想展示一般情况。(带有正确实现的out catch块)可能是在您的案例中最容易使用的,也是最简单的。但是为了展示备选方案,这里有一个版本将“重试”流控制考虑到一个单独的方法中:
// 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);
});
}
当然,您可以通过重试次数、更好的错误传播等改进这一点。使用布尔值
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);
}
}
}
}
很抱歉,我无法抗拒!总是有更好的方法来编写逻辑而不使用goto。@McWafflestix:我不同意。在一些非常罕见的情况下,使用goto
实际上会产生更干净的代码——打破嵌套循环是一个经常被引用的例子(因为C#没有像Java那样标记中断).更多信息,请参见。@Heinzi:好的,你的观点是:在某些非常糟糕的代码情况下,使用goto可以生成更干净的代码;不过,我会将其归类为一种气味,一种特别糟糕的气味。@McWafflestix:这是一种很容易修复的气味。它通常是方法中嵌套深度过大的指示器。不需要bool。更重要的是,这是doeLet’不要抛出最后一次失败。这有无限次的重试,通常不能解决问题。是的,这就是为什么我说了类似的话。这个想法是在循环中进行的,这似乎是这里每个答案的一般想法。对,使用循环是非常明显的(虽然不是普遍的)“魔鬼在细节中。这执行无限的尝试,使用C++语法来捕获,不重启。我不知道为什么它在错误时被重置。哦,而且它在失败时不会重新打开。”Steven Sudit:catch块的体被暗示为与原始代码相同。@ LBukKin,没有一些变化。原始CAtch块在此代码中甚至不会编译。无论如何,这仍然会永远重试,这不是目标。catch块需要关闭
streamwriter!@Anthony:谢谢,这是一个错误。我会立即修复它。我只做了一个我认为适用于任何解决方案的更改:我使它关闭
旧streamwr在打开一个新的解决方案之前进行iter。如果不这样做,那么旧的解决方案将保持一个句柄打开,直到GC启动,阻止新的解决方案工作!我真的不知道该怎么做。可以说,这种委托驱动的解决方案是优雅的、灵活的和可重用的。然后,它目前实际上没有做需要做的事情。最后,我将既不投赞成票,也不投反对票。@Steven:我错过了什么吗?它在哪些方面不符合要求?你提到的方式:没有重试次数,没有最后一次尝试,等等。毫无疑问,你可以做到所需的——我已经看到了足够多的答案,可以肯定这一点——但你现在还没有做到。@Steven:好吧,总之坦白地说,OP从未提到需要执行多次重试,事实上,在编写原始代码时,它只会执行一次重试。至于最后一次尝试的抛出,代码应该这样做,因为动作委托在catch块中被重新调用。如果我们只想重试一次,我们可以跳过所有委托和循环tead硬编码。我希望我们能比这种暴力解决方案做得更好,特别是考虑到它在多次重试中失败。这不可能奏效。首先,NotFailedOnce=!NotFailedOnce)
总是错误的,所以它永远不会抛出。相反,它将永远循环。@Steve,再看一遍代码,它不是一个等式检查,而是一个赋值。这很聪明,意思不好。编译器会为此发出警告,因为谓词中间的赋值很可能是由于输入错误而导致的。同样,通过记下bool而不是将其设置为false,将bool设置为false是聪明的/不好的。这段代码被不必要地混淆了。@Steven-同意if()中的赋值点,我更改了它。但是,NOTing与将其设置为false完全不同。注意确保它只工作一次。感谢您将赋值移出谓词。如果您查看流程,您会发现可能有一个hasfiled
。它将设置在实例化streamwriter的行的正上方。那样就简单多了。而且,不需要其他的(或所有的大括号),因为抛出退出当前流。@Steven:当然,为什么不呢?这是一个简单的尾部递归,可读性很强:Write(body,false)
非常清楚地记录了编写者的意图(再次尝试相同的操作,但不要重试),并且避免了代码混乱(没有循环,没有成功的
变量)。用重试计数替换retryOnError
也是一个简单的练习……原因如下。由于GC的工作方式,递归使对象保持更长的生存时间,因此当迭代解决方案足够清晰时,应该避免递归。当尾部递归优化成为可能时,问题就不那么严重了。这个例子
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);
}
}
}
}