【问题标题】:Is it possible to have one Exception handler for multiple timers in a C# class?是否可以在 C# 类中为多个计时器设置一个异常处理程序?
【发布时间】:2016-06-11 23:30:19
【问题描述】:

我有一个运行系统托盘应用程序的 C# 程序 - 在后台传输/移动/创建/编辑文件。

如果用户手册删除程序正在使用的文件,则有很多异常处理和循环处理以防止程序崩溃/卡住。

不幸的是,其中一台正在运行该程序的计算机发生了程序崩溃。电脑好难弄,不能装调试软件(外边是嵌入式PC,没有网络)。

我已尝试查找崩溃的原因(例如未处理的异常),但没有找到任何东西,也无法访问远程位置的 PC。

我希望找到一种方法来使用 AppDomain / UnhandledExceptionEventHandler 来捕获所有未处理的异常并将它们记录下来以进行诊断。 但是,我(故意)在“DoSomething.class”类中的办公室中创建的异常正在使 WinForm 应用程序崩溃,而不是记录异常错误。

我的代码是:

    //Current domain for the unhandled exception handling
    AppDomain currentDomain;

    [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlAppDomain)]
    public MainForm()
    {
        InitializeComponent();

        currentDomain = AppDomain.CurrentDomain;
        currentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionHandler);


        CreateTimer.Interval = Settings.Default.CreateTimer;
        CreateTimer.Start();
        RunCopyProtocol();

        ChangeFilesTimer.Interval = 10000;
        ChangeFilesTimer.Start();
        RunChangeFiles();

        throw new Exception("ABC");

    }

    public void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args)
    {
        try
        {
            Exception ex = (Exception)args.ExceptionObject;
            SetLabel(ex);
        }
        finally { }
    }

    private string SetLabel(Exception ex)
    {
        String str;

        str = ex.Message;
        Label1.Text = str;

        return str;
    }

    private void ChangeFilesTimer_Tick(object sender, EventArgs e)
    {
        RunChangeFiles();
        throw new Exception("2");
    }

为什么 throw new 异常不调用未处理异常错误? 我将如何使用 AppDomain 获取未处理的异常处理程序来处理 RunChangeFiles 中的这个异常/异常?

AppDomain 上的代码基于MSDN examples

【问题讨论】:

  • 您可能对 AppDomain.UnhandledException 将允许您做什么有一个错误的想法。它不会阻止应用程序在发生未处理的异常时结束。它只是一个通知,允许您在进程结束之前进行清理或记录。

标签: c# winforms exception exception-handling appdomain


【解决方案1】:

如果您的计时器是 System.Timers.Timer,则原因由 MSDN here 记录:

Timer 组件捕获并抑制由事件处理程序为 Elapsed 事件引发的所有异常。

看看这个类似的问题: How do I get the Exception that happens in Timer Elapsed event?

您必须捕获在 elapsed 处理程序中引发的异常,并在 ThreadPool 线程上重新引发它们。

使用上面的代码并扩展引用问题的答案:

private void ChangeFilesTimer_Tick(object sender, EventArgs e)
{
    try
    {
        RunChangeFiles();
    }
    catch (Exception ex)
    {
        ThreadPool.QueueUserWorkItem(
            _ => { throw new Exception("Exception on timer thread.", ex); });
    }
}

如果您的计时器是System.Windows.Forms.Timer,那么您需要挂钩Application.ThreadException 事件来处理未处理的异常。

在致电Application.Run()之前订阅此活动。


您还可以在重新抛出异常之前在本地异常处理块中处理 Exception 的日志记录。

try
{
    /// ...
}
catch (Exception ex)
{
    if (ex is ArgumentException)
    {
        /// handle known or specific exceptions here
    }
    else 
    {
        /// log then rethrow unhandled exceptions here
        logExceptions(ex);
        throw;  
    }
}

【讨论】:

  • 如果我放一个“throw new Exception("TEST");”在 MainForm() 内部。它仍然会抛出异常而不会被处理程序捕获。计时器是否仅通过运行来抑制其他事件? (即不仅在过去时?)
  • 公共 MainForm() { InitializeComponent(); currentDomain = AppDomain.CurrentDomain; currentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionHandler); CreateTimer.Interval = Settings.Default.CreateTimer; CreateTimer.Start();运行复制协议(); ChangeFilesTimer.Interval = 10000; ChangeFilesTimer.Start();运行更改文件(); throw new Exception("123") } 这是代码。处理程序订阅后在 MainForm() 末尾抛出新异常
  • 您在 UI 线程上抛出了测试异常。要处理此问题,您需要挂钩Application.ThreadException 事件。看这里:stackoverflow.com/a/5762806/4267590 和 MSDN here
  • 你是对的,创建“currentDomain”是不必要的。
  • 以前我只在非UI/非定时器线程中使用过AppDomain UnhandledExceptionEventHandler。显然,这比我意识到的要多得多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-04
相关资源
最近更新 更多