c# 异步异常 处理
异常处理是一种处理应用程序中运行时错误的技术。 异步编程使我们能够执行资源密集型操作,而无需在应用程序的主线程或执行线程上进行阻塞。
但是,请注意,异步方法的错误处理机制与同步方法的错误处理机制不同。 本文讨论了在C#中使用异步代码时如何处理异常。
若要使用本文提供的代码示例,您应该在系统中安装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控制台应用程序项目。
- 启动Visual Studio IDE。
- 点击“创建新项目”。
- 在“创建新项目”窗口中,从显示的模板列表中选择“控制台应用程序(.NET Core)”。
- 点击下一步。
- 在接下来显示的“配置新项目”窗口中,指定新项目的名称和位置。
- 单击创建。
这将在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块。 因此,尽管引发了两个异常,但我们只会收到其中一个。
使用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# 异步异常 处理