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)