c# 异步异常 处理_如何在C#中处理异步代码中的异常

c# 异步异常 处理

异常处理是一种处理应用程序中运行时错误的技术。 异步编程使我们能够执行资源密集型操作,而无需在应用程序的主线程或执行线程上进行阻塞。

但是,请注意,异步方法的错误处理机制与同步方法的错误处理机制不同。 本文讨论了在C#中使用异步代码时如何处理异常。

[ 也在InfoWorld上:Microsoft .NET 5:.NET Standard和.NET Core的合并对开发人员意味着什么 ]

若要使用本文提供的代码示例,您应该在系统中安装Visual Studio 2019。 如果您还没有副本,则可以在此处下载Visual Studio 2019

在Visual Studio 2019中创建.NET Core控制台应用程序项目

首先,让我们在Visual Studio中创建一个.NET Core Console Application项目。 假设系统中已安装Visual Studio 2019,请按照以下概述的步骤在Visual Studio 2019中创建新的.NET Core控制台应用程序项目。

  1. 启动Visual Studio IDE。
  2. 点击“创建新项目”。
  3. 在“创建新项目”窗口中,从显示的模板列表中选择“控制台应用程序(.NET Core)”。
  4. 点击下一步。
  5. 在接下来显示的“配置新项目”窗口中,指定新项目的名称和位置。
  6. 单击创建。

这将在Visual Studio 2019中创建一个新的.NET Core控制台应用程序项目。我们将在本文的后续部分中使用此项目。

异步与同步代码中的异常处理

在同步C#代码中,异常在调用堆栈中传播,直到它们到达可以处理该异常的适当的catch块为止。 但是,异步方法中的异常处理不是那么简单。

C#中的异步方法可以具有三种返回值类型:void,Task和Task <TResult>。 当异步方法的返回类型为Task或Task <TResult>时发生异常时,该异常对象将包装在AggregateException的实例中并附加到Task对象。 如果抛出多个异常,则所有异常都存储在Task对象中。

但是,返回类型为void的异步方法没有与之关联的Task对象。 如果在此类方法中引发了异常,则会在调用异步方法时处于活动状态的SynchronizationContext上引发异常。

[ 同样在InfoWorld上:.NET 5.0不会附带的.NET Framework API ]

返回void的异步方法中的异常

以下程序显示了一个异步方法,该方法返回void并引发异常。

public static void ThisIsATestMethod()
        {
            try
            {
                AsyncMethodReturningVoid();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
private static async void AsyncMethodReturningVoid()
        {
            throw new Exception("This is an error message...");
        }

当您执行上面的ThisIsATestMethod()方法时,您会发现未调用调用方法的catch块,即ThisIsATestMethod。

返回Task对象的异步方法中的异常

在返回Task对象的异步方法中引发异常时,这些异常将包装在AggregateException的实例中并返回给调用方法。 当我们等待任务时,我们仅从可能发生的异常列表中获取第一个异常。 下面的程序对此进行了说明。

public static async Task ExceptionInAsyncCodeDemo()
        {
            try
            {
               var task1 = Task.Run(() => throw new IndexOutOfRangeException
                  ("IndexOutOfRangeException is thrown."));
               var task2 = Task.Run(() => throw new ArithmeticException
                  ("ArithmeticException is thrown."));
               await Task.WhenAll(task1, task2);
            }
               catch (AggregateException ex)
            {
               Console.WriteLine(ex.Message);
            }
               catch (Exception ex)
            {
               Console.WriteLine(ex.Message);
            }
        }

当您执行上述方法时,将在控制台窗口中显示消息“抛出IndexOutOfRangeException”。 引发异常后,控件将进入第二个catch块,即使用Exception作为其类型参数的catch块。 因此,尽管引发了两个异常,但我们只会收到其中一个。

[ 通过InfoWorld的App Dev Report新闻通讯了解软件开发中的热门话题 ]

使用Exceptions属性检索所有异常

要检索所有已引发的异常,我们可以利用Task实例的Exceptions属性。 下面的代码清单显示了如何检索返回Task实例的方法中发生的所有异常。

public static async Task ExceptionInAsyncCodeDemo()
        {
            Task tasks = null;
            try
            {
              var task1 = Task.Run(() => throw new IndexOutOfRangeException
                 ("IndexOutOfRangeException is thrown."));
              var task2 = Task.Run(() => throw new
                 ArithmeticException("ArithmeticException is thrown."));
              tasks = Task.WhenAll(task1, task2);
              await tasks;
            }
            catch
            {
                AggregateException aggregateException = tasks.Exception;
                foreach (var e in aggregateException.InnerExceptions)
                {
                    Console.WriteLine(e.GetType().ToString());
                }
            }
        }

使用AggregateException.Handle处理异常

您可以利用AggregateException.Handle来处理某些异常,而同时忽略您不想处理的那些异常。 以下代码段显示了如何实现此目的。

public async static Task ExceptionInAsyncCodeDemo()
        {
            try
            {
                var task1 = Task.Run(() => throw new
                   IndexOutOfRangeException
                   ("IndexOutOfRangeException is thrown."));
                var task2 = Task.Run(() => throw new
                   ArithmeticException
                   ("ArithmeticException is thrown."));
                Task.WaitAll(task1, task2);
            }
            catch (AggregateException ae)
            {
                ae.Handle(ex =>
                {
                    if (ex is IndexOutOfRangeException)
                        Console.WriteLine(ex.Message);
                    return ex is InvalidOperationException;
                });
            }
        }

在上面给出的代码示例中,在忽略InvalidOperationException的同时处理IndexOutOfRangeException。

最后,这是从Program.cs文件的Main方法中调用ExceptionInAsyncCodeDemo()方法的方法。

static async Task Main(string[] args)
        {
            await ExceptionInAsyncCodeDemo();
            Console.Read();
        }

您可以利用异步编程来构建可伸缩且响应Swift的应用程序。 但是,使用异步方法时,请记住,这些方法的错误处理语义与同步方法的语义不同。

翻译自: https://www.infoworld.com/article/3453659/how-to-handle-exceptions-in-asynchronous-code-in-c.html

c# 异步异常 处理

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值