繁体   English   中英

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

[英]Repeating a function in C# until it no longer throws an exception

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

例如:

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

你只需要永远循环:

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 (非常规方法名称,顺便说一句)抛出ArgumentNullException因为你有一个bug并且filter是null ...你真的想永远占用100%的CPU吗?

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

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

使用异常作为控制流程并不是一个好的理想选择,但这可以满足您的要求。

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

您必须将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秒,加上操作时间本身。

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

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

尝试

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

你所追求的行为可能会导致无限循环,如果这永远不会成功...

尝试这样的事情:

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

编辑:哇! 英雄所见略同! :)

虽然我不建议你无数次执行此操作,但你可以用一个句子创建一个单独的函数:

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

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

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

我按照这种模式来解决这个问题:

    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变量来增加或减少这个等待时间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM