如何获取 Timer Elapsed 事件中发生的异常?

发布于 2024-09-24 06:50:43 字数 807 浏览 2 评论 0原文

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

如何获取传递到主应用程序的计时器已用事件处理程序中发生的异常?如果我使用下面的代码,异常将被“吞没”,并且主应用程序永远不会获取它(即使我有 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);
        }
    }

I'm working with Windows Forms application and hava a manager class that uses System.Timers.Timer to periodly check data from database.

How do I get the Exception that occurs in timer Elapsed eventhandler delivered into main application? If I'm using the code below, the exception get's "swallowed", and main application never gets it (even if I have handlers for ThreadException and 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);
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

注定孤独终老 2024-10-01 06:50:43

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

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

If you don't have access to the main thread, you can throw the exception on another, non-timer thread:

catch (Exception exception)
{
    ThreadPool.QueueUserWorkItem(
        _ => { throw new Exception("Exception on timer.", exception); });
}
千笙结 2024-10-01 06:50:43

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

来自 MSDN

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

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

Since System.Timers.Timer swallows any exception thrown in the event handler, you will need to marshal the exception to another thread (probably the UI thread). You could do this via Control.Invoke, or by storing error information in a member variable and having the UI thread check this error information after the operation is complete. If non-null, the UI could then throw.

From MSDN:

In the .NET Framework version 2.0 and
earlier, the Timer component catches
and suppresses all exceptions thrown
by event handlers for the Elapsed
event. This behavior is subject to
change in future releases of the .NET
Framework.

Just checked in .NET 4.0, and this behavior has not yet changed.

饮湿 2024-10-01 06:50:43

您可以将异常分配给局部变量并检查是否抛出异常:

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

You can assign the exception to a local variable and check if an exception has been thrown:

// 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;
    }
屌丝范 2024-10-01 06:50:43

我猜你想处理主窗体上的异常,这个解决方案并不完整,但展示了如何使用“操作”来做到这一点

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

}

I guess that you want to handle the exception on the main form, this solution is not complete but shows how to do it with an "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);
        }
    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文