在C#中重复一个函数,直到它不再抛出异常

时间:2011-10-27 18:37:22

标签: c# exception

我有一个调用SOAP接口的类,并获取一个数据数组。但是,如果此请求超时,则会引发异常。这很好。但是,我希望我的程序再次尝试进行此调用。如果它超时,我希望继续拨打这个电话,直到它成功为止。我怎么能做到这一点?

例如:

try
{
   salesOrdersArray = MagServ.salesOrderList(sessID, filter);
}
catch
{
   ?? What Goes Here to FORCE the above line of code to rerun until it succeeds.
}

11 个答案:

答案 0 :(得分:16)

你只需要永远循环:

while (true)
{
    try
    {
        salesOrdersArray = MagServ.salesOrderList(sessID, filter);
        break; // Exit the loop. Could return from the method, depending
               // on what it does...
    }
    catch
    {
        // Log, I suspect...
    }
}

请注意,您几乎肯定实际上永远循环。您几乎肯定会有最大尝试次数,并且可能只捕获特定的异常。抓住所有异常永远可能会令人震惊......想象如果salesOrderList(非常规方法名称,btw)抛出ArgumentNullException因为你有一个错误和filter为空...你真的想永远占用100%的CPU吗?

答案 1 :(得分:4)

如果您无法更改超时,则以下情况应该有效。 salesOrdersArray应初始化为null

while(salesOrdersArray == null)
{
    try
    {
       salesOrdersArray = MagServ.salesOrderList(sessID, filter);
    }
    catch
    {
       // Log failure
    }
}

答案 2 :(得分:2)

使用异常作为控制流通常不是一个好主意,但这将按照您的要求执行。

bool Caught = true;
while (Caught)
try
{
    salesOrdersArray = MagServ.salesOrderList(sessID, filter);
    Caught = false;
}
catch
{
    Caught = true;
}

答案 3 :(得分:2)

您必须将try / catch块放在循环结构中。如果你不想消耗100%的处理器,那么在catch块中放置一个Thread.Sleep,所以每次发生异常时,它都会等待一段时间,让处理器自由地做其他事情。

// iterate 100 times... not forever!
for (int i = 0; i < 100; i++)
{
    try {
        // do your work here;

        break; // break the loop if everything is fine
    } catch {
        Thread.Sleep(1000);
    }
}

您还可以指定异常类型,以便仅处理超时异常,并传递其他类型的异常。

// iterate 100 times... not forever!
for (int i = 0; i < 100; i++)
{
    try {
        // do your work here;

        break; // break the loop if everything is fine
    } catch (TimeOutException) {
        Thread.Sleep(1000);
    }
}

请注意,TimeOutException应替换为异常的真实名称...我不知道这是否是真实姓名。

同样调整睡眠时间,以毫秒为单位给出,重复次数,在我呈现的情况下,100次重复1000ms产生最长等待1分40秒,加上操作时间本身。

答案 4 :(得分:1)

我将使用事务性队列(MSMQ)来存储服务调用。循环将使消息出列并在TransactionScope中调用服务,如果调用失败,则消息似乎仍在队列中。可以通过在消息中添加到期时间来指定总体超时。如果你真的想要一个可靠的解决方案,这个解决方案是好的,因为我猜这个操作是至关重要的。

答案 5 :(得分:0)

bool repeat = true;
while (repeat)
{
    try
    {
       salesOrdersArray = MagServ.salesOrderList(sessID, filter);
       repeat = false;
    }
    catch
    {
    }
}

答案 6 :(得分:0)

尝试

bool failed = false;
do {
 try
 {
  salesOrdersArray = MagServ.salesOrderList(sessID, filter);
 }
 catch
 {
  failed = true;
 }
} while(failed);

如果从未成功过,那么你所追求的行为可能会导致无限循环......

答案 7 :(得分:0)

尝试这样的事情:

var failed = true;
while (failed)
{
  try 
  {
    salesOrdersArray = MagServ.salesOrderList(sessID, filter); 
    failed = false;
  }
  catch
  {
  }
}
编辑:哇!英雄所见略同! :)

答案 8 :(得分:0)

虽然我不建议你无数次这样做,但你可以用这句话单独编写一个函数:

void GoConnect()
{
    try
    {
        salesOrdersArray = MagServ.salesOrderList(sessID, filter);
    }
    catch
    {
        GoConnect();
    }
}

答案 9 :(得分:0)

while(salesOrdersArray == null){

  try
  {
    salesOrdersArray = MagServ.salesOrderList(sessID, filter);
  }
  catch(salesOrderException e)
  {
     log(e.message);
  }
}

这将永远运行,并且使用异常作为一个缓慢的循环。有没有办法可以修改你的函数,它返回null,而不是抛出异常?如果您希望此调用会定期失败,请不要使用try / catch块。

答案 10 :(得分:0)

我遵循这种模式来解决这个问题:

    public void Send(String data, Int32 attemptNumber)
    {
        try
        {
            yourCodeHere(data);
        }
        catch (WebException ex)
        {
            if (attemptNumber > 0)
                Send(data, --attemptNumber);
            else
                throw new AttemptNumberExceededException("Attempt number exceeded!", ex);
        }
        catch (Exception ex)
        {
            //Log pourpose code goes here!
            throw;
        }
    }

永远尝试似乎不是一个好主意,因为你最终可能会有一个无限的过程。如果您认为您需要多次尝试来实现目标,请在此处设置大量数字。

我个人认为明智的做法是在eac尝试 Thread.Sleep(1000); 之后等待几毫秒,或者在callig 发送(数据)之前; ---你例如,如果您认为它适用于您的场景,可以使用attemptNumber变量来增加或减少此等待时间。