8

私は.NET 4.0でラムダを非同期に実行し、終了時に結果を特定のURIに投稿するWebフックに取り組んでいます。

私はそれを機能させましたが、スローされた例外をタスクで処理したいので、それらが親に到達するのを止めるのが難しいと感じています。

ここに私のコードの一部があります:

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()、実行する継続と実行する継続を登録するために 2 回呼び出しOnlyOnRanToCompletionを行いましたOnlyOnFaulted。(2回呼び出す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);。アサーションを行う前にすべてのタスクが完了していることを確認するために、Task の配列に対する呼び出しを使用していることに言及する必要があります。その呼び出しが違いを生むかどうかはわかりません。タスクによる例外の処理方法。現在、WaitAll は、HandleException 継続関数によって処理されていないため、各タスクの例外を集約する AggregationException をスローします。

4

3 に答える 3

3

タスクの例外を監視するタスクの継続は、例外を処理しません。タスクが終了するのを待っている場所ならどこでも発生します。

アサートする前に WaitAll(tasks) を呼び出していると言いました。十分な時間を与えれば継続が実行されたと思いますが、通常、WaitAll() の例外は継続が実行される前に発生します。したがって、継続が作業を完了する機会が与えられる前に、おそらくアサートは失敗しました。

于 2012-03-13T01:50:06.090 に答える
1

私がこのアプローチを使用するのは、宣言型の流暢なコーディング スタイルを提供し、例外処理の側面でコードを散らかさないためです。

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());
                }
            });
    }
}
于 2015-10-09T18:28:14.713 に答える
1

おそらく、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 が実行されることを保証します。

于 2012-02-10T19:41:15.697 に答える