Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/261.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 编写重试逻辑而无需转到的更好方法_C#_.net_Goto - Fatal编程技术网

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);
                }
            }
      }        
}