异步执行异常捕获 AggregateException
#region 集合异常 AggregateException 用于对付 Task 上的异常
/*
* 在同步调用中可以将方法 包装到 try 然后用 catch 捕获异常,但是异步调用却不能用 try 包装Start()调用来捕获异常,
* 为什么呢?因为异步调用肯定是会牵扯到其他的方法或线程,这时他会跳出 try catch
* 如果是在 try 外面出现的异常呢?emm . 这个时候估计他就用不上了,所以就有了 AggregateException 类来背锅了。
* 只要这个时候抛出异常了,AggregateException 就将异常信息收集 到catch中
* 可能有很多个。。。
*
* 说明书上的解释,异步之所以不能用 try catch 捕捉异常,是因为不能用 try块来包装 start()
* 调用来捕捉异常,因为控制会立即从调用返回,然后控制会离开try 块,而这时距离工作者线程发生异常可能还有好久呢?
* 一个解决方案是将任务的委托主体包装到 try 块中,引发并被工作者线程捕捉的异常不会造成问题,
* 因为try 块在工作者线程尚能正常地工作。但未处理的异常就麻烦了,工作者线程不捕获他们.从CLR 2.0 k开始,
* 任何线程上的未处理异常都会被视为严重错误并造成程序异常终止。所有线程上的所有
* 异常都必须被捕捉,否则不允许程序运行(嗯,这个好)(要处理未处理异常的高级技术,请参见 高级主题 :
* 处理 Thread 上的未处理异常),异步任务中的未处理异常有所不同,在这种情况下,任
* 务调度会用 " catcall" 异常处理程序来包装委托。如果任务引发未处理的异常,catchall 处理程序来包装委托,
* 如果任务引发了未处理的异常,catchall 处理程序会捕捉并记录异常细节,防止CLR自动终止进程
*/
//举个栗子
public class Program
{
public static void Main()
{
Task task = Task.Run(() =>
{
throw new InvalidOperationException(); // 当对象当前状态的方法调用无效时引发的异常。 抛出异常
//由于对象的当前状态,操作无效。
});
try
{
task.Wait();
} // AggregateException 表示在应用程序执行期间发生的一个或多个错误。
catch (AggregateException Exception)// Exception 表示在应用程序执行期间发生的错误。
{
Exception.Handle(eachException =>
{
//eachException 是一个参数。 为每个异常执行的谓词。谓词接受系统作为参数。要处理的异常,并返回一个布尔值,以指示是否处理了异常。
//Console.WriteLine($"ERROR:{ eachException.Source}");//返回当前项目(应用程序)名称
//Console.WriteLine($"ERROR:{ eachException.Message}");// Message 获取描述当前异常的消息。
//Console.WriteLine($"ERROR:{ eachException.StackTrace}");//获取调用堆栈上立即帧的字符串表示形式。 其中显示的行数 就是错误代码行数
//Console.WriteLine($"ERROR:{eachException.InnerException}");//获取当前异常的异常实例
//Console.WriteLine($"ERROR:{eachException.Data}");// 获取提供附加用户定义信息的键/值对集合的例外。 ??????
//Console.WriteLine($"ERROR:{eachException.HResult}");//返回 分配给特定值的编码数值异常。
//Console.WriteLine($"ERROR:{eachException.ToString()}");//获取当前异常消息,并返回堆栈上的错误信息
//Console.WriteLine($"ERROR:{eachException.GetType()}");//获取当前实例的运行时类型。 返回错误类型
//Console.WriteLine($"ERROR:{eachException.HelpLink}");//获取或设置与此异常关联的帮助文件的链接。
//Console.WriteLine($"ERROR:{eachException.TargetSite}");// 获取引发当前异常的方法。
//Console.WriteLine($"ERROR:{eachException.Equals("System.InvalidOperationException")}");//确定指定的对象是否等于当前对象。
//Console.WriteLine($"ERROR:{eachException.GetHashCode()}");//作为默认的哈希函数。
//Console.WriteLine($"ERROR:{eachException.GetObjectData()}"); // 额。。。 SerializationInfo 存储序列化或反序列化对象所需的所有数据。该类不能继承。
//参考资料:https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.iserializable.getobjectdata?redirectedfrom=MSDN&view=netframework-4.8#System_Runtime_Serialization_ISerializable_GetObjectData_System_Runtime_Serialization_SerializationInfo_System_Runtime_Serialization_StreamingContext_
//Console.WriteLine($"ERROR:{eachException.GetBaseException()}");//在派生类重写中返回一个或者多个异常的原因,StackTrace 区别在哪里呢?
return true;
});
}
}
}
#endregion
在async方法中,发生一个异常时,代码并不会直接跳到catch语句中去,而是继续执行,所以到最后catch语句中得到的错误信息是one or more exceptions occurs…
这样的设计给我们带来了麻烦就是传统的try/catch方法得到的无法得到具体的错误信息。
【解决方法】
- 在catch语句中记录错误信息
if (e is AggregateException) { AggregateException ae = (AggregateException)e; ae.Handle((x) => { exception = x.Message; return true; // Let anything else stop the application. }); } else { exception = e.Message; } |
- 在 catch语句中取到AggregateException的信息(类似解决方法1),然后重新抛出一个带有具体错误信息的异常给调用者。
- 将异常转成AggregateException后,可以取到InnerException或者InnerExceptions, 然后再用解决方法1或者2进行处理。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
2014-11-21 jQuery UI的datepicker日期控件如何让他显示中文