如何处理System.Threading.Timer中的异常

时间:2017-08-25 14:03:49

标签: c# .net exception timer

我正在尝试处理异常,但它不起作用! 这个问题是什么?

让我们说在Main i中运行任何参数的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的异常。但它不会抓住它,但为什么呢?我该怎么办呢?

2 个答案:

答案 0 :(得分:0)

Timer在单独的TimerCallback主题上调用ThreadPool。 在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方法中)

答案 1 :(得分: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....")
  }
}