在没有goto的情况下编写重试逻辑的更好方法

Clu*_*der 7 .net c# goto

有没有更好的方法来编写这段代码而不使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*ter 15

这是我将使用的基本逻辑,而不是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);
Run Code Online (Sandbox Code Playgroud)

我刚刚添加了尝试逻辑,尽管原始问题没有.

  • @Steven Sudit:catch块的主体暗示与原始代码相同. (2认同)

Ste*_*dit 5

迈克尔的解决方案并不能完全满足要求,即重试固定次数,抛出最后一次失败.

为此,我建议一个简单的for循环,倒计时.如果成功,请退出break(或者,如果方便的话,返回).否则,让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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,返回会很好,但我想展示一般情况.


LBu*_*kin 5

@Michael 的答案(正确实现了 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);
    });
}
Run Code Online (Sandbox Code Playgroud)

当然,您可以通过重试计数、更好的错误传播等来改进这一点。

  • @Steven:好吧,平心而论,OP 从未提到需要执行多次重试,事实上,在编写原始代码时,它只会执行一次重试。至于抛出最后一次尝试,代码应该这样做,因为在 catch 块中重新调用了动作委托。 (2认同)