简体   繁体   English

捕获异步回调中抛出的异常

[英]Catching an exception thrown in an asynchronous callback

I have a method that takes a callback argument to execute asynchronously, but the catch block doesn't seem to be catching any exceptions thrown by the synchronous call ( this.Submit refers to a synchronous method). 我有一个方法,它采用一个回调参数异步执行,但catch块似乎没有捕获同步调用抛出的任何异常( this.Submit指的是一个同步方法)。

public void Submit(FileInfo file, AnswerHandler callback)
{
    SubmitFileDelegate submitDelegate = new SubmitFileDelegate(this.Submit);
    submitDelegate.BeginInvoke(file, (IAsyncResult ar) =>
    {
        string result = submitDelegate.EndInvoke(ar);
        callback(result);
    }, null);
}

Is there a way to catch the exception thrown by the new thread and send it to the original thread? 有没有办法捕获新线程抛出的异常并将其发送到原始线程? Also, is this the "proper" way to handle async exceptions? 另外,这是处理异步异常的“正确”方法吗? I wrote my code so it could be called like this (assuming the exception issue is fixed): 我编写了我的代码,因此可以像这样调用(假设异常问题已修复):

try
{
    target.Submit(file, (response) =>
    {
        // do stuff
    });
}
catch (Exception ex)
{
    // catch stuff
}

but is there a more proper or elegant way to do this? 但有没有更合适或更优雅的方式来做到这一点?

If you're targeting .NET 4.0, you can utilize the new Task Parallel Library, and observe the Task object's Exception property. 如果您的目标是.NET 4.0,则可以使用新的任务并行库,并观察Task对象的Exception属性。

public Task Submit(FileInfo file)
{
    return Task.Factory.StartNew(() => DoSomething(file));
}

private void DoSomething(FileInfo file)
{
    throw new Exception();
}

Then use it like this: 然后像这样使用它:

Submit(myFileInfo).ContinueWith(task =>
{
    // Check task.Exception for any exceptions.

    // Do stuff with task.Result
});

where DoSomething is the method you'd like call asynchronously, and the delegate you pass to ContinueWith is your callback. DoSomething是您想要异步调用的方法,而传递给ContinueWith的委托是您的回调。

More information about exception handling in TPL can be found here: http://msdn.microsoft.com/en-us/library/dd997415.aspx 有关TPL中异常处理的更多信息,请访问: http//msdn.microsoft.com/en-us/library/dd997415.aspx

This is not a 'best practice' solution, but I think it's a simple one that should work. 这不是一个“最佳实践”解决方案,但我认为这应该是一个简单的解决方案。

Instead of having the delegate defined as 而不是将委托定义为

private delegate string SubmitFileDelegate(FileInfo file);

define it as 将其定义为

private delegate SubmitFileResult SubmitFileDelegate(FileInfo file);

and define the SubmitFileResult as follows: 并按如下方式定义SubmitFileResult:

public class SubmitFileResult
{
    public string Result;
    public Exception Exception;
}

Then, the method that actually does the file submission (not shown in the question) should be defined like this: 然后,实际执行文件提交的方法(未在问题中显示)应该像这样定义:

private static SubmitFileResult Submit(FileInfo file)
{
    try
    {
        var submissionResult = ComplexSubmitFileMethod();

        return new SubmitFileResult { Result = submissionResult };
    }
    catch (Exception ex)
    {
        return new SubmitFileResult {Exception = ex, Result = "ERROR"};
    }
}

This way, you'll examine the result object, see if it has the Result or the Exception field set, and act accordingly. 这样,您将检查结果对象,查看它是否设置了Result或Exception字段,并相应地执行操作。

In short, no. 简而言之,没有。

When you call submitDelegate.BeginInvoke , it spawns the new thread, returns, and promptly exits your try/catch block (while the new thread runs in the background). 当你调用submitDelegate.BeginInvoke ,它会生成新线程,返回并立即退出你的try / catch块(当新线程在后台运行时)。

You could, however, catch all unhandled exceptions like this: 但是,您可以捕获所有未处理的异常,如下所示:

AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(YourException);

This will catch everything in the application domain, however (not just your async method). 这将捕获应用程序域中的所有内容(但不仅仅是您的异步​​方法)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM