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

kev*_*314 9 c# lambda asynchronous callback

我有一个方法,它采用一个回调参数异步执行,但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);
}
Run Code Online (Sandbox Code Playgroud)

有没有办法捕获新线程抛出的异常并将其发送到原始线程?另外,这是处理异步异常的"正确"方法吗?我编写了我的代码,因此可以像这样调用(假设异常问题已修复):

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

但有没有更合适或更优雅的方式来做到这一点?

Adi*_*ter 9

如果您的目标是.NET 4.0,则可以使用新的任务并行库,并观察Task对象的Exception属性.

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

private void DoSomething(FileInfo file)
{
    throw new Exception();
}
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它:

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

    // Do stuff with task.Result
});
Run Code Online (Sandbox Code Playgroud)

DoSomething你想要异步调用的方法在哪里,你传递给的委托ContinueWith就是你的回调.

有关TPL中异常处理的更多信息,请访问:http://msdn.microsoft.com/en-us/library/dd997415.aspx


Cri*_*scu 8

这不是一个"最佳实践"解决方案,但我认为这应该是一个简单的解决方案.

而不是将委托定义为

private delegate string SubmitFileDelegate(FileInfo file);
Run Code Online (Sandbox Code Playgroud)

将其定义为

private delegate SubmitFileResult SubmitFileDelegate(FileInfo file);
Run Code Online (Sandbox Code Playgroud)

并按如下方式定义SubmitFileResult:

public class SubmitFileResult
{
    public string Result;
    public Exception Exception;
}
Run Code Online (Sandbox Code Playgroud)

然后,实际执行文件提交的方法(未在问题中显示)应该像这样定义:

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"};
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,您将检查结果对象,查看它是否设置了Result或Exception字段,并相应地执行操作.


Mar*_*ius 5

简而言之,不。

当您调用 时submitDelegate.BeginInvoke,它会生成新线程、返回并立即退出 try/catch 块(同时新线程在后台运行)。

但是,您可以捕获所有未处理的异常,如下所示:

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

然而,这将捕获应用程序域中的所有内容(不仅仅是您的异步​​方法)。