9

例外とログが原因でタスクが終了したときにキャッチすることは可能ですか? 処理を追加しましCurrentDomain_UnhandledExceptionたが、これは役に立ちません。

いつものようにタスクを作成しますTask.Factory.StartNew()。そのようなタスク例外のどこかで発生すると、静かにクラッシュします(ただし、永久に動作するはずですが、LongRunningオプションも使用しています)。だから私はそのような行動について通知を受けたい.

理想的には、例外が原因でタスクがクラッシュしたときに通知されるように、どこかにオプションを設定したいと考えています。

それが不可能な場合は、作成するタスクに何かを追加する必要がありますか? もちろんtry{} finally{}、各タスク内に大きなブロックを追加することもできますが、おそらくもっと良い解決策がありますか?

4

5 に答える 5

6

Test実行する as Taskがあると仮定します。

static int Test()
{
    throw new Exception();
}
  1. 最初のアプローチ -呼び出し元のスレッドで例外を処理する:

    Task<int> task = new Task<int>(Test);
    task.Start();
    
    try
    {
        task.Wait();
    }
    catch (AggregateException ex)
    {
        Console.WriteLine(ex);
    }
    

    注: 例外のタイプは AggregateException になります。すべての実際の例外は、ex.InnerExceptionsプロパティを通じて入手できます。

  2. 2 番目のアプローチ -一部のタスクのスレッドで例外を処理する:

    を次のように定義しExceptionHandlerます。

    static void ExceptionHandler(Task<int> task)
    {
        var ex = task.Exception;
        Console.WriteLine(ex);
    }
    

    使用法:

    Task<int> task = new Task<int>(Test);
    task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
    task.Start();
    

リファレンス:方法: タスクによってスローされた例外を処理する

于 2012-11-13T09:32:29.187 に答える
2

自分で作成したタスクの場合、かなり単純です: を呼び出す独自のメソッドを作成しますが、タスクを返す前にTask.Factory.StartNew()も呼び出します。Task.ContinueWith(loggingDelegate, TaskContinuationOptions.OnlyOnFaulted

問題は、C# 5 の非同期メソッドなど、他のインフラストラクチャによって作成されたタスクの障害ハンドラーが追加されないことです。ただし、それでも役立つ場合があります。

を使用することもできますがTaskScheduler.UnobservedTaskException、名前のとおり、他の何かによってまだ観察されていない例外に対してのみ呼び出されます。(繰り返しますが、それはあなたにとって良いことかもしれません...)

于 2012-11-13T09:30:43.713 に答える
2

例外発生時の動作を行う拡張メソッドを利用できます。これは、Task が Faulted になったときに発生します。したがって、続行する別のタスクがある場合、次のタスクは前のタスクが失敗したかどうかを確認し、例外をログに記録できます。

私は通常、次の方法を使用します。

//If you want to chain more tasks..
public static Task<T> Continue<T>(this Task<T> task, Action<T> action)
{
    if (!task.IsFaulted)
    {
        task.ContinueWith((t) => action(t.Result), TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion);
    }
    return task;
}

public static Task OnException(this Task task, Action<Exception> onFaulted)
{
    task.ContinueWith(c =>
    {
        var excetion = c.Exception;
            onFaulted(excetion);
    },
        TaskContinuationOptions.OnlyOnFaulted |
        TaskContinuationOptions.ExecuteSynchronously);
    return task;
}

したがって、次を使用できます。

Task.Factory.StartNew(...).OnException(ex => Log(ex));

それが役に立てば幸い。

于 2012-11-13T09:31:38.370 に答える
0

例外を監視し、問題をログに記録/報告する Task に OnlyOnFaulted 継続を作成できます。

t.ContinueWith(task =>
{
    // Report and log error
}, System.Threading.CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());

上記のコードは、 のため、UI スレッドでタスクを実行しますTaskScheduler.FromCurrentSynchronizationContext()。これは、winforms を使用していて、ユーザーに通知する必要がある場合に必要になることがあります。

于 2012-11-13T09:32:38.020 に答える
0

task.Wait()try/catch ブロックと catch でラップしますAggregateException。このようなもの -

Task<string[]> task1 = Task<string[]>.Factory.StartNew(() => GetAllFiles(path));

// Use this line to throw an exception that is not handled.
try
{
    task1.Wait();
}
catch (AggregateException ae)
{

    ae.Handle((x) =>
    {
        if (x is UnauthorizedAccessException) // This we know how to handle.
        {
            Console.WriteLine("You do not have permission to access all folders
                                in this path.");
            Console.WriteLine("See your network administrator or try
                                another path.");
            return true;
        }
        return false; // Let anything else stop the application.
    }); 
}

詳細はここにあります -タスクによってスローされた例外を処理します

于 2012-11-13T09:31:29.953 に答える