簡體   English   中英

我希望任務處理所有引發的異常,但是發現很難阻止它們到達父級

[英]I want the Task to handle any exceptions that are thrown, but am finding it difficult to stop them from reaching the parent

我正在.NET 4.0中的Web Hook上工作,該Web Hook將異步運行lambda,然后在完成后將結果發布到給定的URI。

我已經做到了,但是現在我希望Task處理所有拋出的異常,並且發現很難阻止它們到達父級。

這是我的代碼的一部分:

private readonly Func<T> _startTask;
private readonly string _responseUri;

public Task<T> Begin()
{
    var task = new Task<T>(_startTask);
    task.ContinueWith<T>(End);
    task.Start();
    return task;
}

private T End(Task<T> task)
{
    if (task.IsFaulted)
    {
        return HandleException(task);
    }

    var result = task.Result;
    WebHookResponse.Respond(result, _responseUri);
    return result;
}

private T HandleException(Task<T> task)
{
    WebHookResponse.HandleException(task.Exception.InnerException, _responseUri);
    return null;
}

我嘗試過的另一種版本調用ContinueWith()兩次,以注冊一個延續以運行OnlyOnRanToCompletion而另一個則運行OnlyOnFaulted (我不確定兩次調用ContinueWith()是否正確。):

public Task<T> Begin()
{
    var task = new Task<T>(_startTask);
    task.ContinueWith<T>(End, TaskContinuationOptions.OnlyOnRanToCompletion);
    task.ContinueWith<T>(HandleException, TaskContinuationOptions.OnlyOnFaulted);
    task.Start();
    return task;
}

private T End(Task<T> task)
{
    var result = task.Result;
    WebHookResponse.Respond(result, _responseUri);
    return result;
}

private T HandleException(Task<T> task)
{
    WebHookResponse.HandleException(task.Exception.InnerException, _responseUri);
    return null;
}

因此,基本上,我希望每個任務都可以通過延續函數處理自己的異常。 就目前而言,在上述兩個示例中都從未調用過HandlException延續函數。

我在測試用例中引起異常,我應該提到我正在使用Tasks.WaitAll(tasks); 在進行我的斷言之前,請調用一系列任務以確保所有任務均已完成,並且我不確定該調用是否對任務處理異常的方式有所不同。 當前,WaitAll引發一個AggregationException,該異常會聚合每個Task的異常,因為HandleException連續函數沒有處理這些異常。

觀察任務異常的任務延續不會處理該異常。 每當您等待任務完成時,它仍然會發生。

您說您在斷言之前正在調用WaitAll(tasks)。 我敢打賭,如果您給它足夠的時間,您的延續將可以運行,但是WaitAll()上的異常通常會在繼續運行之前發生。 因此,您的斷言可能在您的延續有機會完成其工作之前就失敗了。

我使用這種方法是因為它提供了一種很好的聲明性流利的編碼風格,並且不會在異常處理方面使您的代碼亂七八糟。

class Program
{
    static void Main()
    {
        Task.Factory.StartNew(
            () =>
                {
                    throw new Exception();
                })
            .Success(() => Console.WriteLine("Works"))
            .Fail((ex) => Console.WriteLine("Fails")).Wait();

        Console.ReadKey();
    }
}

public static class TaskExtensions
{
    public static Task Success(this Task task, Action onSuccess)
    {
        task.ContinueWith((t) =>
        {
            if (!t.IsFaulted)
            {
                onSuccess();
            }
        });

        return task;
    }

    public static Task Fail(this Task task, Action<Exception> onFail)
    {
        return task.ContinueWith(
            (t) =>
            {
                if (t.IsFaulted)
                {
                    t.Exception.Handle(x => true);
                    onFail(t.Exception.Flatten());
                }
            });
    }
}

也許,對於Henk Holterman的回答, 順序有所不同。 那是,

var task = new Task<T>(_startTask);
task = task.ContinueWith<T>(HandleException, TaskContinuationOptions.OnlyOnFaulted);
task = task.ContinueWith<T>(End, TaskContinuationOptions.OnlyOnRanToCompletion);
task.Start();

將確保HandleException將在必要時運行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM