简体   繁体   English

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

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

I've got a class that calls a SOAP interface, and gets an array of data back. 我有一个调用SOAP接口的类,并获取一个数据数组。 However, if this request times out, it throws an exception. 但是,如果此请求超时,则会引发异常。 This is good. 这很好。 However, I want my program to attempt to make this call again. 但是,我希望我的程序再次尝试进行此调用。 If it times out, I'd like it to keep making this call until it succeeds. 如果它超时,我希望继续拨打这个电话,直到它成功为止。 How can I accomplish this? 我怎么能做到这一点?

For example: 例如:

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

You just need to loop forever: 你只需要永远循环:

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...
    }
}

Note that you should almost certainly not actually loop forever. 请注意,您几乎肯定不会真正循环。 You should almost certainly have a maximum number of attempts, and probably only catch specific exceptions. 您几乎肯定会有最大的尝试次数,并且可能只捕获特定的异常。 Catching all exceptions forever could be appalling... imagine if salesOrderList (unconventional method name, btw) throws ArgumentNullException because you've got a bug and filter is null... do you really want to tie up 100% of your CPU forever? 永远捕获所有异常可能会令人震惊......想象一下,如果salesOrderList (非常规方法名称,顺便说一句)抛出ArgumentNullException因为你有一个bug并且filter是null ...你真的想永远占用100%的CPU吗?

If you can't change the timeout, the below should work. 如果您无法更改超时,则以下情况应该有效。 salesOrdersArray should be initialized to null . salesOrdersArray应初始化为null

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

It its not gernally a good idead to use exceptions as control flow, but this will do what you requested. 使用异常作为控制流程并不是一个好的理想选择,但这可以满足您的要求。

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

You must place the try/catch block inside a loop construct. 您必须将try / catch块放在循环结构中。 If you wish not to consume 100% of your processor place a Thread.Sleep in the catch block, so everytime an exception occurs, it will wait some time, freeing the processor to do other things. 如果你不想消耗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);
    }
}

You could also specify exception type, so that only the timeout exception is handled, and other kinds of exceptions pass-through. 您还可以指定异常类型,以便仅处理超时异常,并传递其他类型的异常。

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

Note that, TimeOutException should be replaced by the real name of the exception... I don't know if that is the real name. 请注意,TimeOutException应该替换为异常的真实名称...我不知道这是否是真实姓名。

Also adjust the sleep time, given in millisecs and the amount of repeats, in the case I presented, 100 repeats of 1000ms yields a maximum wait of 1 minute and 40 seconds, plus the operation time itself. 同时调整睡眠时间,以毫秒为单位,重复次数,在我提出的情况下,100次重复1000ms产生最长等待1分40秒,加上操作时间本身。

I will use a transactional queue (MSMQ) to store the service call. 我将使用事务性队列(MSMQ)来存储服务调用。 A loop will dequeue messages and call the service in a TransactionScope, if the call fails the message appear to be still in the queue. 循环将使消息出列并在TransactionScope中调用服务,如果调用失败,则消息似乎仍在队列中。 An ov erall timeout can be specified by adding a time to expire in the message. 可以通过在消息中添加到期时间来指定总体超时。 This solution is good if you really want a reliable solution since I guessed that calling that operation is critical. 如果你真的想要一个可靠的解决方案,这个解决方案是好的,因为我猜这个操作是至关重要的。

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

Try 尝试

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

The behavior you are after might cause an endless loop if this never succeeds though... 你所追求的行为可能会导致无限循环,如果这永远不会成功...

Try something like this: 尝试这样的事情:

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

Edit: Wow! 编辑:哇! Great minds think alike! 英雄所见略同! :) :)

Although I would NOT recommend you to do this for an infinite number of times, you could make a separate function out of that one sentence: 虽然我不建议你无数次执行此操作,但你可以用一个句子创建一个单独的函数:

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

This will run forever, and is using exceptions as a loop which is slow. 这将永远运行,并使用异常作为一个缓慢的循环。 Is there a way you can modify your function that it returns null, instead of throwing an exception? 有没有办法可以修改你的函数,它返回null,而不是抛出异常? If you're expecting that this call will fail regularly, don't use a try/catch block. 如果您希望此调用会定期失败,请不要使用try / catch块。

I follow this pattern in order to solve this problem: 我按照这种模式来解决这个问题:

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

Trying forever seems not to be a good idea as you may end up having an infinite process. 永远尝试似乎不是一个好主意,因为你最终可能会有一个无限的过程。 If you think you need many attempts to achieve your goal just set huge number here. 如果您认为您需要多次尝试来实现目标,请在此处设置大量数字。

I personally think its wise to wait some milliseconds, or seconds after eac attempt Thread.Sleep(1000); 我个人认为在eac尝试Thread.Sleep(1000)之后等待几毫秒或者几秒钟是明智的 before callig Send(data); 在callig 发送之前(数据); --- you could for example, use the attempNumber variable to increse or decrease this waiting time if you think its wise for your scenario. ---例如,如果你认为它适用于你的场景,你可以使用attemptNumber变量来增加或减少这个等待时间。

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

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