【问题标题】:How do I get the Exception that happens in Timer Elapsed event?如何获取 Timer Elapsed 事件中发生的异常?
【发布时间】:2015-06-09 19:28:21
【问题描述】:

我正在使用 Windows 窗体应用程序,并且有一个管理器类,它使用 System.Timers.Timer 定期检查数据库中的数据。

如何将计时器 Elapsed 事件处理程序中发生的异常传递到主应用程序?如果我使用下面的代码,异常会被“吞下”,而主应用程序永远不会得到它(即使我有 ThreadException 和 UnHandledException 的处理程序)。

// Main Form
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

// Manager class
private System.Timers.Timer _timer;

    void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        try
        {
            doSomeDatabaseActions();
        }
        catch (Exception ex)
        {
            throw new ApplicationException("How do I get this error back into main thread...", ex);
        }
    }

【问题讨论】:

    标签: c# multithreading timer


    【解决方案1】:

    如果您无权访问主线程,您可以在另一个非定时器线程上抛出异常:

    catch (Exception exception)
    {
        ThreadPool.QueueUserWorkItem(
            _ => { throw new Exception("Exception on timer.", exception); });
    }
    

    【讨论】:

    • 不错。这会保留堆栈跟踪并将异常泵送到 AppDomain.UnhandledException。谢谢!
    • 我有一个使用这种方法的无限循环。异常总是由AppDomain.UnhandledException 抛出和处理。我怎样才能避免这种情况?
    • 这需要将整个函数包装在 try catch 块中吗?
    • @MonsterMMORPG 是的,就像问题中一样。
    • 这在稍微不同的上下文中对我有用,Windows 服务内的工作线程抛出异常。由于线程是由计时器 Elapsed 事件启动的,因此发生了同样的事情。
    【解决方案2】:

    由于System.Timers.Timer 吞没了事件处理程序中抛出的任何异常,您需要将异常编组到另一个线程(可能是 UI 线程)。您可以通过Control.Invoke 执行此操作,或者通过将错误信息存储在成员变量中并让UI 线程在操作完成后检查此错误信息。如果不是null,则 UI 可能会抛出异常。

    来自MSDN

    在 .NET Framework 2.0 版和 早些时候,Timer 组件捕获 并抑制所有抛出的异常 通过 Elapsed 的事件处理程序 事件。此行为受 .NET 未来版本的变化 框架。

    刚刚签入 .NET 4.0,此行为尚未改变。

    【讨论】:

    • 我想我明白了,我将异常传递给我的主线程上的一个函数,然后该函数在重新抛出异常之前在函数上使用了 this.Invoke()。我理解正确吗?
    • 在 .net 4.5 中是否有任何新方法可以捕获意外错误?它仍然会吞咽,并且无论如何都不会在不将整个 _timer_Elapsed 包装在 try catch 中的情况下记录错误?
    【解决方案3】:

    您可以将异常分配给局部变量并检查是否引发了异常:

    // Main Form
    Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
    AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
    
    // Manager class
    private System.Timers.Timer _timer;
    
        private exception = null;
    
        void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            //reset the exception in case object is reused.
            this.exception = null;
            try
            {
                doSomeDatabaseActions();
            }
            catch (Exception ex)
            {
                this.exception = ex;
            }
        }
    
        /**
        * Checks whether the exception object is set.
        */
        public bool hasExceptionOccured(){
            return (this.exception != null);
        }
    
        //The main application will call this to get the exception.
        public Exception getException(){
            return this.exception;
        }
    

    【讨论】:

      【解决方案4】:

      我猜你想在主窗体上处理异常,这个解决方案并不完整,但展示了如何使用“Action”来完成它

      using System;
      using System.Timers;
      
      
      public class MainForm
      {
          public MainForm()
          {
              var tm = new TestManager(exception =>
              {
                  //do somthing with exception
                  //note you are still on the timer event thread
              });
      
          }
      }
      
      public class TestManager
      {
          private readonly Action<Exception> _onException;
      
          public TestManager(System.Action<System.Exception> onException )
          {
              _onException = onException;
      
          }
      
      
          private System.Timers.Timer _timer;
          void _timer_Elapsed(object sender, ElapsedEventArgs e)
          {
              try
              {
                  doSomeDatabaseActions();
              }
              catch (Exception ex)
              {
                  //throw new ApplicationException("How do I get this error back into main thread...", ex);
                  _onException(ex);
              }
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 2016-04-24
        • 1970-01-01
        • 2014-03-02
        • 2023-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多