C#中的try...catch语句在异步操作中发生异常时无法捕获异常

3
例如:
第一步:绑定UnhandledException事件。
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

第二步:

try
    {
       //at here,do asynchronous operation and throw a exception.
    }
catch (Exception ex)
   {
            Console.WriteLine("error");
   }

当异步操作抛出异常时,捕获代码不会被调用,只有UnhandledException事件被触发,在结束事件被调用后才退出应用程序。

我希望在catch语句中捕获任何异常并避免退出应用程序。

=======================================================

异步代码是异步套接字操作。在套接字异步接收消息事件(BeginReceive、EndReceive)中,我抛出了一个OverflowException。

throw new OverflowException("chunk size too long.");

=============================================

你说得对,现在我在异步操作中捕获异常并将其传递给原始类(这意味着异常将在同一线程上抛出,可以尝试...catch语句将被调用)。


你如何启动异步操作?你应该参考所使用的工具关于使操作异步的文档。其中一些工具可能会将异常转发到调用线程,而另一些则可能不会,并依赖于操作捕获所有异常,一些(例如:新的 async/await 方式)甚至可能会吞噬异常。 - Vlad
3个回答

2

默认情况下,异步任务将在与其实例化时不同的上下文中运行。因此,try/catch块在这种情况下无效。

可以这样理解:

Worker worker = new HouseMaid();
try
{
    worker.DoSomeWork();
}
catch(WorkerIsSickException ex)
{
    worker.TakeMedicin();
    worker.StopWorkingAndRestForAWhile();
}

在这里,我们可以看到当工人生病时,工作流程会中断并且异常将被处理。然而,当我们进行以下操作时:

Worker worker = new HouseMaid();
try
{
    Worker otherWorker = new HouseMaidHelper();

    worker.DelegateWorkTo(otherWorker, CallBackWhenOTherWorkerIsDone);

    worker.GoOnDoSomethingElse();
}
catch(WorkerIsSickException ex)
{
    worker.TakeMedicin();
    worker.StopWorkingAndRestForAWhile();
}

try/catch块是一种安全网,只适用于当前的worker,而不适用于其他的worker。其他worker有它自己的作用域。如果其他worker失败了,这并不意味着当前的worker也必须承担后果。


更重要的是,在一般情况下,执行DelegateWorkTo方法的人可能已经完成了GoOnDoSomethingElse并完全退出catch块,然后HouseMadeHelper在遇到任何问题之前就会出现。在许多模式中,如果调用WaitForHelperToFinish方法并且助手已经抛出异常或最终在完成之前抛出异常,则WaitForHelperToFinish方法将指示,通常通过抛出包装助手异常的异常。 - supercat
如果我错了,请纠正我。在其他线程中抛出的异常直到您等待其完成(即Join)才会传播。然而,未处理的异常事件对我来说是新的,因此我认为它可以或不能捕获在其他线程上抛出的异常,具体取决于某些情况。也许它在退出时被捕获,因为垃圾回收将尝试等待任务完成或中止。 - Prometheus

2
你的问题不是很清楚,但如果是异步操作引发了异常,那么你展示的代码可能在异常抛出之前就已经完成了 - 毕竟它是异步的,对吧?
基本上,异步让你重新思考错误处理 - 以及你如何处理取决于你的异步方式。通常你会在回调中捕获异常 - 或者甚至不需要捕获它,而是使用类似Task.Status的东西来检查它。
诚然,C# 5中关于异步方面的所有工作应该使得其中一些变得更容易,但你仍然需要考虑异步。

0
异步操作将成功启动,因此执行将继续成功并错过您的异常处理程序。如果您想在异步操作中捕获异常,您需要在异步执行的代码中进行异常处理。然后,如果您想在原始类中处理异常,可以将回调放入原始类的函数中。

好的,我的理想是异步操作抛出异常,原始类可以通过try...catch语句捕获它。我只是不想在异步操作中处理异常。 - springchun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接