Skip to content

C# 多线程 05-使用 C#6.0 05-处理异步操作中的异常

🏷️ 《C# 多线程》

处理异步操作中的异常

csharp
/// <summary>
/// 处理异步操作中的异常
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
    Task t = AsynchronousProcessing();
    t.Wait();

    Console.ReadLine();
}

static async Task AsynchronousProcessing()
{
    Console.WriteLine("1. 单个异常");
    Console.WriteLine("   使用 try/catch 捕获单个异常");
    try
    {
        string result = await GetInfoAsync("任务 1", 2);
        Console.WriteLine(result);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception details: {ex}");
    }

    Console.WriteLine();
    Console.WriteLine("2. 多个异常");
    Console.WriteLine("   尝试使用 try/catch 捕获多个异常,但此种写法仅能捕获其中一个异常");
    
    Task<string> t1 = GetInfoAsync("任务 1", 3);
    Task<string> t2 = GetInfoAsync("任务 2", 2);
    try
    {
        string[] results = await Task.WhenAll(t1, t2);
        Console.WriteLine(results.Length);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception details: {ex}");
    }

    Console.WriteLine();
    Console.WriteLine("3. 使用 AggregateException 捕获多个异常");
    Console.WriteLine("   从 task 的 Exception 属性中获取多个异常的信息");
    
    t1 = GetInfoAsync("任务 1", 3);
    t2 = GetInfoAsync("任务 2", 2);
    Task<string[]> t3 = Task.WhenAll(t1, t2);
    try
    {
        string[] results = await t3;
        Console.WriteLine(results.Length);
    }
    catch
    {
        var ae = t3.Exception.Flatten();
        var exceptions = ae.InnerExceptions;
        Console.WriteLine($"Exceptions caght: {exceptions.Count}");
        foreach (var e in exceptions)
        {
            Console.WriteLine($"Exception details: {e}");
            Console.WriteLine();
        }
    }

    Console.WriteLine();
    Console.WriteLine("4. 在 catch 和 finally 块中使用 await");
    Console.WriteLine("   c#6.0中,允许在catch和finally块中使用await,在之前的版本中这种写法会报错");
    Console.WriteLine("   若将语言版本改为C#5.0编译,则会报如下错误:");
    Console.WriteLine("     CS1985 无法在 catch 子句中等待");
    Console.WriteLine("     CS1984  无法在 finally 子句体中等待");
    
    try
    {
        string result = await GetInfoAsync("任务 1", 2);
        Console.WriteLine(result);
    }
    catch (Exception ex)
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
        Console.WriteLine($"Catch block with await: Exception details: {ex}");
    }
    finally
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
        Console.Write("Finally block");
    }
}

static async Task<string> GetInfoAsync(string name, int seconds)
{
    await Task.Delay(TimeSpan.FromSeconds(seconds));
    throw new Exception($"Boom from {name}");
}

打印结果

txt
1. 单个异常
   使用try/catch捕获单个异常
Exception details: System.Exception: Boom from 任务 1
   在 Recipe5_5.Program.<GetInfoAsync>d__2.MoveNext() 位置 C:\Users\liujiajia\So
urce\Repos\learn-multi-threading\Recipe5-5\Program.cs:行号 101
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
   在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot
ification(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   在 Recipe5_5.Program.<AsynchronousProcessing>d__1.MoveNext() 位置 C:\Users\li
ujiajia\Source\Repos\learn-multi-threading\Recipe5-5\Program.cs:行号 26

2. 多个异常
   尝试使用try/catch捕获多个异常,但此种写法仅能捕获其中一个异常
Exception details: System.Exception: Boom from 任务 1
   在 Recipe5_5.Program.<GetInfoAsync>d__2.MoveNext() 位置 C:\Users\liujiajia\So
urce\Repos\learn-multi-threading\Recipe5-5\Program.cs:行号 101
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
   在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot
ification(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   在 Recipe5_5.Program.<AsynchronousProcessing>d__1.MoveNext() 位置 C:\Users\li
ujiajia\Source\Repos\learn-multi-threading\Recipe5-5\Program.cs:行号 42

3. 使用AggregateException捕获多个异常
   从task的Exception属性中获取多个异常的信息
Exceptions caght: 2
Exception details: System.Exception: Boom from 任务 1
   在 Recipe5_5.Program.<GetInfoAsync>d__2.MoveNext() 位置 C:\Users\liujiajia\So
urce\Repos\learn-multi-threading\Recipe5-5\Program.cs:行号 101
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
   在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot
ification(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   在 Recipe5_5.Program.<AsynchronousProcessing>d__1.MoveNext() 位置 C:\Users\li
ujiajia\Source\Repos\learn-multi-threading\Recipe5-5\Program.cs:行号 59

Exception details: System.Exception: Boom from 任务 2
   在 Recipe5_5.Program.<GetInfoAsync>d__2.MoveNext() 位置 C:\Users\liujiajia\So
urce\Repos\learn-multi-threading\Recipe5-5\Program.cs:行号 101


4. 在catch和finally块中使用await
   c#6.0中,允许在catch和finally块中使用await,在之前的版本中这种写法会报错
   若将语言版本改为C#5.0编译,则会报如下错误:
     CS1985 无法在 catch 子句中等待
     CS1984  无法在 finally 子句体中等待
Catch block with await: Exception details: System.Exception: Boom from 任务 1
   在 Recipe5_5.Program.<GetInfoAsync>d__2.MoveNext() 位置 C:\Users\liujiajia\So
urce\Repos\learn-multi-threading\Recipe5-5\Program.cs:行号 101
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
   在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot
ification(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   在 Recipe5_5.Program.<AsynchronousProcessing>d__1.MoveNext() 位置 C:\Users\li
ujiajia\Source\Repos\learn-multi-threading\Recipe5-5\Program.cs:行号 83
Finally block