C# Task异常捕获


一般情况下,调用Task的Wait(),WaitAny(),WaitAll(),或者等待Result即可捕获AggregateException异常

Task task = new Task(() =>
{
  throw new Exception("异步方法发生异常!")
});
task.Start();

try
{
    task.Wait();
}
catch(AggregateException ex)
{
    //打印异常具体信息
}

但是在异步方法中使用Wait强制阻塞当前线程,只是为了捕获异常,这种迷之操作吾辈不屑之。思来想去,想到一个折中的方法,在Task的后续任务中捕获异常,客官请看:

Task task = new Task(() =>
{
    throw new InvalidOperationException("并行任务中发生未知异常。");
});
task.Start();

Task endTsk = task.ContinueWith((task) =>
{
    throw task.Exception;
},TaskContinuationOptions.OnlyOnFaulted);

try
{
    endTsk.Wait();
}
catch(AggregateException ex)
{
    foreach(var er in ex.InnerExceptions)
    {
        Console.WriteLine($"异常类型{er.InnerException.GetType()}\n" +
                          $"异常来源:{er.InnerException.Source}\n" +
                          $"异常内容:{er.InnerException.Message}");
	}
}
Console.WriteLine("程序结束");
Console.ReadKey();

在后续任务中等待并捕获异常是一个能够接受的结果,而且等待的时间几乎可以忽略不计。
当然,作为攻城狮,对于完美代码的追求是不懈的,有没有更合理的方式呢?
回答是Yes,就是使用事件通知来进行异常捕获,如下所示:

public class AggregateExceptionArgs:EventArgs
{
    public AggregateException Exception {get;set;}
}



public static event EventHandler<AggregateExceptionArgs> AggregateExceptionCatched;

static void Main(string[] args)
{
    AggregateExceptionCatched += program_OnAggregateExcept;
    Task.Run(() =>
    {
        try
        {
            throw new ArgumentException("task参数异常!");
        }
        catch (Exception ex)
        {
            AggregateExceptionArgs exArgs = new AggregateExceptionArgs
            {
                Exception = new AggregateException(ex)
            };
            AggregateExceptionCatched(null, exArgs);
        }
    });
}

static void program_OnAggregateExcept(Object sender, AggregateExceptionArgs ex)
{
    foreach (var innEx in ex.Exception.InnerExceptions)
    {
        Console.WriteLine($"异常信息:{innEx.Message}");
    }
}

以上例子中,我定义了一个事件参数AggregateExceptionArgs,一个事件AggregateExceptionCatched,在主线程中,我为事件定义了事件处理方法program_OnAggregateExcept,当捕获到异常时,将调用处理方法。
这种方式完全不会阻塞当前线程,如果是在winForm或者WPF窗体应用程序中,还能将异常交付UI线程处理。因为墙裂推荐这种方式捕获异常。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM