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

时间:2012-01-05 19:39:13

标签: c# asynchronous lambda 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);
}

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

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

但是有更合适或更优雅的方法吗?

3 个答案:

答案 0 :(得分: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();
}

然后像这样使用它:

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

    // Do stuff with task.Result
});

其中DoSomething是您要异步调用的方法,而传递给ContinueWith的代理是您的回调。

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

答案 1 :(得分:8)

这不是“最佳实践”解决方案,但我认为这是一个应该有效的简单解决方案。

而不是将委托定义为

private delegate string SubmitFileDelegate(FileInfo file);

将其定义为

private delegate SubmitFileResult SubmitFileDelegate(FileInfo file);

并按如下方式定义SubmitFileResult:

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

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

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"};
    }
}

这样,您将检查结果对象,看它是否设置了Result或Exception字段,并相应地采取行动。

答案 2 :(得分:3)

简而言之,没有。

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

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

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

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