深入理解 c# 第十五章 异步方法中断的参数验证 在抛出异常时进行包装

时间:2022-11-27 00:45:32
    class BrokenArgumentValidation
    {
        static void Main()//异步方法中断的参数验证
        {
            MainAsync().Wait();
        }

        static async Task MainAsync()
        {
            Task<int> task = ComputeLengthAsync(null);//故意传入错误的参数
            Console.WriteLine("Fetched the task");
            int length = await task;//等待结果
            Console.WriteLine("Length: {0}", length);
        }

        static async Task<int> ComputeLengthAsync(string text)
        {
            if (text == null)
            {
                throw new ArgumentNullException("text");//立即抛出异常
            }
            await Task.Delay(500); // 模拟真实的异步工作
            return text.Length;
        }
    }


  与迭代器类似,参数验证会有些麻烦。假设我们在验证完参数不含有空值后,想在异步
方法里做一些处理。像在同步代码那样验证参数,那么在等待任务之前,调用者不会得到
任何错误提示。  
  在失败之前会先输出Fetched the task。实际上,输出这条结果之前,异常就已经同步地
抛出了,这是因为在验证语句之前并不存在await表达式。但调用代码知道等待返回的任务时,
才能看到这个异常。一般来说,参数验证无需耗时太久(或导致其他异步操作)。最好在
系统陷入更大的麻烦之前,立即报告失败的存在。


输出
Fetched the task
Exception: System.Reflection.TargetInvocationException: 调用的目标发生了异常。 ---> System.AggregateException: 发生一个 或多个错误。 ---> System.ArgumentNullException: 值不能为 null。
参数名: text
   在 Chapter15.BrokenArgumentValidation.<ComputeLengthAsync>d__5.MoveNext() 位置  位置省略本BrokenArgumentValidation.cs:行号 27
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
   在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   在 Chapter15.BrokenArgumentValidation.<MainAsync>d__0.MoveNext() 位置 BrokenArgumentValidation.cs:行号 19 位置省略
   --- 内部异常堆栈跟踪的结尾 ---
   在 System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   在 System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
   在 System.Threading.Tasks.Task.Wait()
   在 Chapter15.BrokenArgumentValidation.Main() 位置 BrokenArgumentValidation.cs:行号 12 位置省略
   --- 内部异常堆栈跟踪的结尾 ---
   在 System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   在 System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   在 System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   在 System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   在 MiscUtil.ApplicationChooser.Run(Type type, String[] args)