尝试捕获每行代码而不使用单独的try-catch块

我目前没有这个问题 ,但你永远不知道,并认为实验总是很有趣。

忽略你的架构甚至要尝试这个问题所必须遇到的明显问题 ,让我们假设你有一些别人设计的可怕编写代码,你需要在相同的代码中做一堆广泛而多样的操作阻止,例如:

WidgetMaker.SetAlignment(57); contactForm["Title"] = txtTitle.Text; Casserole.Season(true, false); ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true; 

乘以一百。 其中一些可能有效,另一些可能会出错。 你需要的是C#相当于“on next resume next”,否则你将最终复制并粘贴许多代码行的try-catches。

你会如何解决这个问题?

很明显,你在VB.NET中编写代码,实际上有On Error Resume Next ,并将它导出到DLL中C#。 其他任何东西都只是一种惩罚的贪婪。

 public delegate void VoidDelegate(); public static class Utils { public static void Try(VoidDelegate v) { try { v(); } catch {} } } Utils.Try( () => WidgetMaker.SetAlignment(57) ); Utils.Try( () => contactForm["Title"] = txtTitle.Text ); Utils.Try( () => Casserole.Season(true, false) ); Utils.Try( () => ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true ); 

重构为个别的,命名良好的方法:

 AdjustFormWidgets(); SetContactTitle(txtTitle.Text); SeasonCasserole(); 

每个都得到适当的保护。

我会说什么都不做

是的,没事。

你已经清楚地向我发现了两件事:

  1. 你知道这个架构很糟糕。
  2. 有很多这种废话。

我说:

  • 没做什么。
  • 添加一个全局error handling程序,以便每次出现繁荣时向您发送电子邮件。
  • 等到有什么东西翻倒(或测试失败)
  • 纠正( 在页面范围内根据需要重构)。
  • 每次出现问题时重复。

如果情况那么糟糕,你马上就可以清理它。 是的,我知道这听起来很糟糕,你可能会开始用错误修正你的头发,但它会允许你在(大量) 代码之前修复有需要/错误的代码,这些代码可能实际上正在工作,无论它有多糟糕看起来。

一旦你开始赢得战争,你将有更好的处理代码(由于你的所有重构)你将有一个更好的想法为它赢得设计..

试图将所有这些包装在气泡包装中可能需要很长时间才能完成,你仍然不会更接近解决问题。

快速失败

详细说来,我想我正在质疑这个问题。 如果抛出exception,为什么您希望代码只是继续,好像什么也没发生? 您可能希望在某些情况下出现exception,在这种情况下,您可以围绕该代码编写try-catch块并处理它们,或者出现意外错误,在这种情况下,您应该更喜欢应用程序中止,重试或失败。 不像受伤的僵尸呻吟’大脑’那样继续。

这是预处理器有用的事情之一。 您可以定义一个吞下exception的宏,然后使用快速脚本将该宏添加到所有行。

所以,如果这是C ++,你可以这样做:

 #define ATTEMPT(x) try { x; } catch (...) { } // ... ATTEMPT(WidgetMaker.SetAlignment(57)); ATTEMPT(contactForm["Title"] = txtTitle.Text); ATTEMPT(Casserole.Season(true, false)); ATTEMPT(((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true); 

不幸的是,似乎没有多少语言包含像C / C ++那样的预处理器。

您可以创建自己的预处理器并将其添加为预构建步骤。 如果您觉得完全自动化它,您可能会编写一个预处理器,它将获取实际的代码文件并自行添加try / catch内容(因此您不必手动将这些ATTEMPT()块添加到代码中) 。 确保它只修改了它应该是困难的行(必须跳过变量声明,循环结构等,以免你破坏构建)。

但是,我认为这些都是可怕的想法,永远不应该这样做,但问的问题是。 🙂

真的,你不应该这样做。 您需要找到导致错误的原因并进行修复。 吞咽/忽略错误是一件坏事,所以我认为这里的正确答案是“修复错误,不要忽视它!”。 🙂

On Error Resume Next在C#世界中是一个非常糟糕的主意。 也不会添加相当于On Error Resume Next实际上帮助你。 它所做的只是让你处于一个糟糕的状态,这可能会导致更微妙的错误,数据丢失和可能的数据损坏。

但是为了让提问者得到应有的答案,你可以添加一个全局处理程序并检查TargetSite以查看哪个方法已经过了。 然后你至少可以知道它是什么线路。 接下来的部分是试图找出如何设置“下一个语句”的方式与调试器的工作方式相同。 希望你的筹码在这一点上不会被解开,或者你可以重新创造它,但它肯定值得一试。 但是,根据这种方法,代码必须每次都以调试模式运行,以便包含调试符号。

正如有人提到的,VB允许这样做。 如何在C#中以同样的方式做到这一点? 输入可靠的reflection器:

这个:

 Sub Main() On Error Resume Next Dim i As Integer = 0 Dim y As Integer = CInt(5 / i) End Sub 

转化为:

 public static void Main() { // This item is obfuscated and can not be translated. int VB$ResumeTarget; try { int VB$CurrentStatement; Label_0001: ProjectData.ClearProjectError(); int VB$ActiveHandler = -2; Label_0009: VB$CurrentStatement = 2; int i = 0; Label_000E: VB$CurrentStatement = 3; int y = (int) Math.Round((double) (5.0 / ((double) i))); goto Label_008F; Label_0029: VB$ResumeTarget = 0; switch ((VB$ResumeTarget + 1)) { case 1: goto Label_0001; case 2: goto Label_0009; case 3: goto Label_000E; case 4: goto Label_008F; default: goto Label_0084; } Label_0049: VB$ResumeTarget = VB$CurrentStatement; switch (((VB$ActiveHandler > -2) ? VB$ActiveHandler : 1)) { case 0: goto Label_0084; case 1: goto Label_0029; } } catch (object obj1) when (?) { ProjectData.SetProjectError((Exception) obj1); goto Label_0049; } Label_0084: throw ProjectData.CreateProjectError(-2146828237); Label_008F: if (VB$ResumeTarget != 0) { ProjectData.ClearProjectError(); } } 

重写代码。 尝试找到逻辑上相互依赖的语句集,这样如果一个语句失败,那么下一个语句就没有意义了,如果你想忽略它们的结果,那么将它们放到自己的函数中并将它们放在它们周围。那并继续。

这可以帮助您识别问题最多的部分。

@ JB King感谢您提醒我。 Logging应用程序块具有可用于跟踪事件的Instrumentation事件,您可以在MS Enterprise库文档中找到更多信息。

 Using (New InstEvent)  End Using 

此使用中的所有步骤都将跟踪到一个日志文件,您可以解析它以查看日志中断的位置(ex被抛出)并识别高级违规者。

重构真的是你最好的选择,但如果你有很多,这可以帮助你找出最严重的罪犯。

可以使用goto,但它仍然很混乱。

我实际上想要一段时间的单一语句try-catch。 在某些情况下它会很有用,例如添加日志代码或者如果它失败则不想中断主程序流。

我怀疑可以使用与linq相关的一些function来完成某些function,但目前还没有时间研究它。 如果您可以找到一种将语句包装为匿名函数的方法,那么使用另一个方法在try-catch块中调用它可以工作……但不确定是否可能。

如果您可以让编译器为此代码提供表达式树,那么您可以通过用包装原始语句的新try-catch块替换每个语句来修改该表达式树。 这并不像听起来那么牵强; 对于LINQ,C#获得了将lambda表达式捕获为表达式树的能力,这些表达式树可以在运行时在用户代码中进行操作。

如果没有其他原因,只能在System.Linq.Expressions中缺少“try”语句,这种方法今天不可能使用.NET 3.5。 但是,一旦完成DLR和LINQ表达式树的合并,它在未来的C#版本中可能是可行的。

为什么不在c#中使用reflection? 您可以创建一个反映代码的类,并使用行#s作为每个try / catch块中放置内容的提示。 这有一些优点:

  1. 它稍微不那么丑陋,因为它实际上并不需要破坏你的源代码,你只能在调试模式下使用它。
  2. 在实现c#时,你会学到一些有趣的东西。

但是我建议不要使用任何一个,除非你正在接管某些工作的维护,你需要处理exception,以便你可以修复它们。 虽然写作可能很有趣。

有趣的问题; 非常可怕

如果你可以使用宏,那就太好了。 但这是对C#的抨击,所以你可以通过一些预处理器工作或一些外部工具来解决它,将你的行包装在单独的try-catch块中。 不确定你是否意味着你不想手动包装它们或者你想完全避免try-catch。

弄清楚这一点,我尝试标记每一行并从一个捕获中跳回来,没有太多运气。 但是, 克里斯托弗发现了正确的方法 。 在Dot Net Thinking和Mike Stall的.NET博客上有一些有趣的额外讨论 。

编辑:当然。 列出的try-catch / switch-goto解决方案实际上不会编译,因为try标签超出了catch范围。 任何人都知道什么是缺少这样的东西编译?

您可以使用编译器预处理步骤自动执行此操作,也可以修改Mike Stall的Inline IL工具以注入一些错误 – 无知。

( Orion Adrian关于检查exception并尝试设置下一条指令的答案也很有趣。)

总而言之,这似乎是一项有趣且富有启发性的练习。 当然,你必须决定在什么时候模拟ON ERROR RESUME NEXT的努力超过了修复代码的努力。 🙂

捕获应用程序的UnhandledException事件中的错误。 这样,甚至可以将未处理的exec记录为发件人以及开发人员合理的任何其他信息。

不幸的是,你可能运气不好。 On Error Resume Next是一个遗留选项,通常非常不鼓励,并且与C#中的知识不相同。

我建议将代码保留在VB中(听起来这是源代码,根据您对OnError ResumeNext的特定请求)以及与C#dll或exe接口,以实现您需要的任何新代码。 然后执行重构以使代码安全,并在执行此操作时将此安全代码转换为C#。

您可以查看集成企业库的exception处理组件,以了解如何处理未处理的exception。

如果这是针对ASP.Net应用程序的,那么Global.asax中有一个名为“Application_Error”的函数,在大多数情况下会被调用,而另一种情况通常是灾难性故障。

忽略你想要避免这样做的所有原因…….

如果只是需要保持线条数量下降,你可以尝试以下方法:

 int totalMethodCount = xxx;
 for(int counter = 0; counter 

但是,如果您尝试重用调用的任何结果,则必须密切关注变量范围。

Hilite每一行,一次一个,’环绕’尝试/捕获。 这避免了你提到的复制粘贴