【发布时间】:2017-08-06 16:29:21
【问题描述】:
已尽可能简化此问题以尝试隔离问题。我假设它与单独线程中引发的异常有关
让有一个 WindowsFormApp。
假设 Program 类源代码如下所示
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionOccurred);
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(UnhandledExceptionOccurred);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
public static void UnhandledExceptionOccurred(object sender, UnhandledExceptionEventArgs e)
{
var x = (Exception)e.ExceptionObject;
MessageBox.Show("Unhandled Exception\r\n" + x.Message);
}
public static void UnhandledExceptionOccurred(object sender, ThreadExceptionEventArgs e_thread)
{
var x = e_thread.Exception;
MessageBox.Show("Thread Exception\r\n" + x.Message);
}
}
对不起,如果这已经是压倒性的。让我尝试为这篇文章中发生的事情进行简化,以积累知识。
静态方法UnhandledExceptionOccurred() 有一个覆盖。这些方法用作未处理线程异常和来自主线程的未处理异常的事件处理程序。 (如果这不正确,我想对此进行更正,但这就是我的理解)。
假设在主窗体中,当单击按钮时抛出异常
private void button1_Click(object sender, EventArgs e)
{
throw new Exception("Exception 1");
}
假设按钮被点击。异常在消息框读取时被很好地捕获
“线程异常异常1”
现在(几乎完成)假设在 Form1 的构造函数中,我创建了一个 System.Timers.Timer,其间隔为 5000 毫秒,并带有一个事件处理程序,用于处理引发异常的已用事件。
System.Timers.Timer T;
public Form1()
{
InitializeComponent();
T = new System.Timers.Timer();
T.Interval = 5000; //Miliseconds;
T.Elapsed += new ElapsedEventHandler(TimerElapsed);
T.Start();
}
以及事件处理程序:
public void TimerElapsed(object sender, ElapsedEventArgs e)
{
T.Stop();
throw new Exception("Exception From Timer Elapsed");
}
现在假设表单已启动,经过了 5 秒。
没有出现消息框,也没有弹出 WindowsFormError 框。程序默默地吞下了异常,我可以单击前面提到的按钮并像以前一样出现一个消息框。
这是怎么回事?
我知道这可能与定时器的线程处理有关。我已经搜索和搜索,但还没有找到一种方法来访问计时器正在使用的线程的内部,以便我可以为其 UnhandledException 和 ThreadException 事件添加一些事件处理程序。
也许我可以使用System.Threading.Timers Timer。
我注意到这种类型的计时器的构造函数采用CallbackMethod? (什么是回调方法?)也许这个回调方法可以用来将未处理的异常路由回MainUI线程?
感谢任何/所有输入。
【问题讨论】:
-
这是
System.Timers.Timer的一个已知问题——计时器回调中任何未处理的异常都会被框架吞没。 始终在System.Timers.Timer回调中提供您自己的异常处理程序。或者,确实,不要使用System.Timers.Timer。如果您要使用System.Threading.Timer,请注意differences。 -
您是否有理由不为此使用
System.Windows.Forms.Timer? -
您还可以将当前计时器上的
SynchronizingObject设置为(也许)您的Form对象。然后,这将在 UI 线程上调用回调,并且异常不会被吞没。 -
@lesscode 没有特别的原因。并且设置同步对象似乎已经解决了这个问题。谢谢
标签: c# multithreading exception timer visual-studio-2017