【问题标题】:Create a guaranteed exception safe method in C#在 C# 中创建有保证的异常安全方法
【发布时间】:2018-03-22 15:10:52
【问题描述】:

我最近实现了一个使用 JSON.SerializeObject 记录对象内容的函数。

长话短说,我们的想法是,这个函数将用于我们新实现的日志记录机制,根据系统参数化在需要时跟踪对象。

整个日志记录机制的一个绝对要求是它永远不应该抛出异常,因为它会被广泛使用。任何开发人员都应该能够使用它,并且在任何情况下,此功能都不应导致代码流中断。如果失败,任何调用都应该被跳过。

在实现它并检查并处理了我能想到的每个异常之后,我决定将整个功能包装在一个外部 try-catch 块中,以防万一。

像这样:

public static void TrackObject(object obj)
{
   try { Console.WriteLine(JsonConvert.SerializeObject(obj)); }
   catch { Console.WriteLine("Failed to track object."); }
}

在顺利通过所有测试后,我启动了主应用程序来进行一些实际的环境测试。 令我惊讶的是,由于 Nuget 配置错误,我的函数在被调用之后但在它进入 try-catch 块之前引发了异常 (System.IO.FileLoadException),因此它传播回主应用程序,从而对代码造成严重破坏流。

这让我开始思考。

有一些方法可以在调用函数时但在处理程序启动之前引发异常。也有一些情况是无法接受异常的。

我当前的解决方案是创建一个包装函数,它只是在 try-catch 中调用实际函数。但这看起来丑陋和错误。另外,我不确定它是否是防弹解决方案。

public static void TrackObject(object obj)
{
   try { PrivateTrackObject(obj); }
   catch { Console.WriteLine("Failed to track object."); }
}

private static void PrivateTrackObject(object obj)
{
   Console.WriteLine(JsonConvert.SerializeObject(obj));
}

有没有办法创建一个防弹、无路可走、无异常的方法?

或者至少是否有明确的方法调用可能发生的异常列表?

PS。编译器警告我版本不匹配,但我第一次没有看到。

PS2。我已经为任何希望看到这个问题的人创建了一个示例项目。 https://drive.google.com/open?id=15BDrLNn87gsMHc9pQ-TgyDMSLQxDBq18

【问题讨论】:

  • 如果有办法创建“无异常”方法,那么异常将不复存在。我不得不承认,我还是不太明白你在问什么,但你的问题似乎太宽泛了
  • 编写永不失败的代码是非常不明智的。严重偏头痛,当它确实失败并且你有零线索找出原因时。幸运的是,这种微弱的尝试让抖动吹了一个覆盆子,所以它仍然可以告诉你出了什么问题。它只花了你几分钟。功能,而不是错误。
  • @maccettura 虽然由于我的回答中提到的原因,您无法从程序中消除 all 异常,但您当然可以构建自己的代码以使用不同的错误处理机制比例外。例如,您可以使用错误代码来指示错误而不是异常(甚至可能从您调用的任何框架代码中捕获所有异常并将其转换为返回的错误代码)。虽然有些人(包括我自己)喜欢使用异常处理错误的模型,但这并不意味着它是设计应用程序的唯一方法。
  • @Servy 我将 OP 的问题解释为您回答的第一部分(即无法创建无异常方法),但我也同意您的评论(还有其他方法可以指示错误)。
  • @Hans Passant 我完全同意你的观点。但有时一段代码会做一些非必要的事情(也就是说,你可以在没有它的情况下继续工作)。我的特定实现正是这样做的。我的问题是我的函数内部发生了异常,但我无法处理它。

标签: c# exception exception-handling


【解决方案1】:

有没有一种方法可以创建一个防弹、无路可走、无异常的方法?

没有。即使该方法实际上是空的,如果堆栈上没有足够的空间来调用该方法,您总是可以抛出线程中止异常,或者堆栈溢出异常,或者它可能导致内存不足异常。

是否有明确的方法调用可能发生的异常列表?

如果是任意代码(即来自委托),则不是。它总是可能是您编写代码时甚至不存在的某种类型的自定义异常。


还请注意,在您的情况下,如果您只想尝试处理正常异常(与上面提到的不同),您需要关注可能在您的 catch 块中引发的任何可能的异常这发生在您的try 块中。仅记录异常可能会失败。在您使用控制台的示例中,标准输出可能存在导致异常的问题。如果你真的想要这段代码永远不会抛出,你需要尝试记录异常,但是当它们不工作时有其他备份日志选项(如果你真的不能throw,正如其他人所提到的,几乎可以肯定是一个坏主意,那么如果记录异常失败,您需要愿意继续不记录)。

【讨论】:

  • 感谢您的回复。实际代码相当广泛。它使用 NLog,回退到自定义机制,该机制也回退到 Trace.WriteLine(只是为了报告异常)。 “不例外”是一个深思熟虑的决定。如果您无法登录,请告知它(何时以及为什么),以便可以修复它,但不要弄乱程序执行。我的问题与如何确保没有不利影响的意外问题(例如参考版本不匹配)不会弄乱整个应用程序有关?您提到的示例(StackOverflowException)无论如何都会影响应用程序。
  • @Phasmagon 根据定义,您不能期望并防止所有意外问题。您可以预期并防止您想到的某些特定问题。
  • 是的。但是你能想象我的雇主(以及我)将被置于什么位置,如果我或质量保证部门错过了这种错误并在客户的环境中发现了它?作为旁注,这种类型的日志记录主要用于与外部服务集成的应用程序的一部分,我们“盲目地”编码(使用 API 参考和开发指南而不实际连接到它们),所以我们的 QA 无法捕获大多数那里的问题。这个特定问题很容易识别和解决。让我担心的是会抛出什么其他我没有想到的异常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-24
  • 1970-01-01
  • 1970-01-01
  • 2013-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多