2017-08-25 57 views
-1

我想處理異常,但它不起作用! 最新的問題?如何處理System.Threading.Timer中的異常

讓我們說在Main中我使用任何參數運行SetUpTimer。

private void SetUpTimer(TimeSpan alertTime, string name) 
{ 

    DateTime current = DateTime.Now; 
    TimeSpan timeToGo = alertTime - current.TimeOfDay; 
    try 
    { 
    Timer timer = new Timer(x => RunReportTask(name),null, timeToGo, Timeout.InfiniteTimeSpan)); 

    catch(Exception e) 
    { 
    Console.WriteLine("Log Exception....") 
    } 
} 

private void RunReportTask(string name) 
{ 

    Console.WriteLine("\r\n\r\nSTART Task \t\tReport: " + name); 

    //DELAY 25 sec 
    Task.Delay(25000); 

    if (name.Equals("Report A") || name.Equals("Report D") || name.Equals("Report F")) 
    { 
    throw new Exception("Task failed!!!"); 
    } 
    else 
    { 
    Console.WriteLine("Task: \t\t" + name + "\tDONE."); 
    } 
} 

所以現在如果我執行它會拋出一個異常與報告名稱A,D,F。但它不會抓住它,但爲什麼?我能做些什麼呢?

+1

您是嘗試/捕獲僅創建計時器,操作的不執行。你可以把所有的代碼放在try/catch中的Action「RunReportTask」中,或者你可以在你的應用中註冊一個[uncaughtExceptionHandler](https://csharp.2000things.com/tag/unhandled-exceptions/)。 – Fildor

+0

將try/catch放在拋出異常的同一個方法中是沒有意義的,但這就是所有可以用你發佈的代碼完成的方法。據推測,隨着更多的信息,它將清楚你如何處理錯誤,但這些信息不在這裏,所以這個問題有太多可能的答案。 –

回答

0

Timer在單獨的ThreadPool線程上調用TimerCallback。 在TimerCallback方法中引發的異常不會傳播到創建定時器的代碼/線程(它們只是'失望')。 如果你想在你的回調方法之外處理它們:你應該在回調方法中捕獲它們並使用一些機制在原始線程中重新拋出或處理它們。 我個人喜歡這個IProgress

有許多在原始代碼的語法錯誤,而是基於對下面的例子應該工作:

private Timer timer; 

public void SetUpTimer(DateTime alertTime, string name) 
{ 

     var progress = new Progress<Exception>((e) => 
        { 
         // handle exception form timercallback here, or just rethrow it... 
         throw e; 
        }); 

     DateTime current = DateTime.Now; 
     TimeSpan timeToGo = (alertTime - current); 
     timer = new Timer(x => RunReportTask(name, progress), 
       null, timeToGo, Timeout.InfiniteTimeSpan); 
    } 

    private void RunReportTask(string name, IProgress<Exception> progress) 
    { 

     try 
     { 

      Console.WriteLine("\r\n\r\nSTART Task \t\tReport: " + name); 

      //DELAY 25 sec 
      Task.Delay(25000); 

      if(name.Equals("Report A") || name.Equals("Report D") || name.Equals("Report F")) 
      { 
       throw new Exception("Task failed!!!"); 
      } 
      else 
      { 
       Console.WriteLine("Task: \t\t" + name + "\tDONE."); 
      } 
     } 
     catch(Exception e) 
     { 
      progress.Report(e); 
     } 
    } 

警告:除了語法,還有與代碼中的一個重要問題你例。只要您希望將其激活,就必須保留對Timer實例的引用。只要Timer超出範圍,它就成爲垃圾收集的候選對象。 在你的例子中,Timer是一個局部變量,只要方法結​​束,它就會超出範圍。如果在alertTime之前收集垃圾,將永遠不會調用TimerCallback。出於這個原因,我已將您的Timer晉升到您班級的私人領域。

此外,當你不再需要Timer,你應該叫Dispose()Timer釋放其資源(例如,在Dispose梅索德爲你的類)。

+0

謝謝,是的,我知道語法是壞的,但我很急(:(。我明天會檢查這個例子,然後再給你檢查:)再次感謝 – Amsel

0

試試這個(因爲你沒有在try塊未關閉括號):

private void SetUpTimer(TimeSpan alertTime, string name) 
{ 

    DateTime current = DateTime.Now; 
    TimeSpan timeToGo = alertTime - current.TimeOfDay; 
    try 
    { 
    Timer timer = new Timer(x => RunReportTask(name),null, timeToGo, Timeout.InfiniteTimeSpan)); 
    } 
    catch(Exception e) 
    { 
    Console.WriteLine("Log Exception....") 
    } 
}