簡體   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