ExceptionExtensions.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. namespace MeloongCore.Extensions;
  2. public static class ExceptionExtensions {
  3. /// <summary>
  4. /// 提取 <paramref name="ex"/> 与其 InnerException 的详细描述与堆栈信息。返回内容总是多于一行。
  5. /// </summary>
  6. /// <param name="showAllStacks">是否必须显示所有堆栈。通常用于判定堆栈信息。</param>
  7. public static string GetDetail(this Exception? ex, bool showAllStacks = false) {
  8. if (ex is null) return "无可用错误信息!";
  9. // 获取最底层的异常
  10. var outerEx = ex;
  11. var innerEx = ex;
  12. while (innerEx.InnerException is not null) innerEx = innerEx.InnerException;
  13. // 获取各级错误的描述与堆栈信息
  14. var descList = new List<string>();
  15. bool isInner = false;
  16. while (ex is not null) {
  17. descList.Add((isInner ? "→ " : "") + ex.Message.ReplaceLineEndings("\r\n", true));
  18. if (ex.StackTrace is not null) {
  19. foreach (string stack in ex.StackTrace.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)) {
  20. if (showAllStacks || stack.ContainsIgnoreCase("pcl"))
  21. descList.Add(stack.ReplaceLineEndings(""));
  22. }
  23. }
  24. if (ex.GetType().FullName != "System.Exception")
  25. descList.Add(" 错误类型:" + ex.GetType().FullName);
  26. ex = ex.InnerException;
  27. isInner = true;
  28. }
  29. // 构造输出信息
  30. string? usualReason = AnalyzeUsualReason(innerEx, outerEx, descList);
  31. if (usualReason is not null) {
  32. return usualReason + "\r\n\r\n————————————\r\n详细错误信息:\r\n" + descList.Join("\r\n");
  33. }
  34. return descList.Join("\r\n");
  35. }
  36. /// <summary>
  37. /// 提取 <paramref name="ex"/> 与其 InnerException 的描述,汇总到一行。
  38. /// </summary>
  39. public static string GetBrief(this Exception? ex) {
  40. if (ex is null) return "无可用错误信息!";
  41. // 获取最底层的异常
  42. var outerEx = ex;
  43. var innerEx = ex;
  44. while (innerEx.InnerException is not null) innerEx = innerEx.InnerException;
  45. // 获取各级错误的描述
  46. var descList = new List<string>();
  47. while (ex is not null) {
  48. descList.Add(ex.Message.ReplaceLineEndings(" ", true));
  49. ex = ex.InnerException;
  50. }
  51. descList = descList.Distinct().ToList();
  52. // 构造输出信息
  53. string? usualReason = AnalyzeUsualReason(innerEx, outerEx, descList);
  54. if (usualReason is not null)
  55. return usualReason + "详细错误:" + descList.First();
  56. descList.Reverse();
  57. return descList.Join(" ← ");
  58. }
  59. private static string? AnalyzeUsualReason(Exception innerEx, Exception outerEx, List<string> descList) {
  60. if (innerEx is TypeLoadException or BadImageFormatException or MissingMethodException or NotImplementedException or TypeInitializationException)
  61. return "PCL 的运行环境存在问题。请尝试重新安装 .NET Framework 4.8 然后再试。若无法安装,请先卸载较新版本的 .NET Framework,然后再尝试安装。";
  62. if (innerEx is UnauthorizedAccessException)
  63. return "PCL 的权限不足。请尝试右键 PCL 选择以管理员身份运行。";
  64. if (innerEx is OutOfMemoryException)
  65. return "你的电脑运行内存不足,导致 PCL 无法继续运行。请在关闭一部分不需要的程序后再试。";
  66. if (innerEx is COMException)
  67. return "由于操作系统或显卡存在问题,导致出现错误。请尝试重启 PCL。";
  68. if (innerEx is System.Net.Sockets.SocketException && descList.Any(l => l.Contains("WSAStartup")))
  69. return "请尝试卸载中国移动云盘,然后再试。";
  70. if (outerEx.IsNetworkRelated())
  71. return "你的网络环境不佳,请稍后再试,或使用 VPN 改善网络环境。";
  72. return null;
  73. }
  74. /// <summary>
  75. /// 判断某个 <paramref name="ex"/> 是否为网络问题所导致。
  76. /// </summary>
  77. public static bool IsNetworkRelated(this Exception ex) {
  78. // 提取 Message(不能用 GetDetail,因为堆栈的方法参数中就有 timeout 字样)
  79. string detail = "";
  80. var cur = ex;
  81. detail += cur.Message;
  82. while (cur.InnerException is not null) {
  83. cur = cur.InnerException;
  84. detail += cur.Message;
  85. }
  86. // 判断
  87. if (detail.Contains("(403)")) return false;
  88. return new[] {
  89. "(408)", "超时", "timeout", "网络请求失败", "连接尝试失败", "远程主机强迫关闭了",
  90. "远程方已关闭传输流", "未能解析此远程名称", "由于目标计算机积极拒绝", "基础连接已经关闭"
  91. }.Any(k => detail.ContainsIgnoreCase(k));
  92. }
  93. }