我目前没有这个问题,但你永远不知道,并认为实验总是很有趣。
忽略你的架构甚至要尝试这个时必须遇到的明显问题,让我们假设你有一些别人设计的可怕编写的代码,你需要做一个在同一代码块中进行各种各样的操作,例如:
WidgetMaker.SetAlignment(57);
contactForm["Title"] = txtTitle.Text;
Casserole.Season(true, false);
((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true;
乘以一百。其中一些可能有效,另一些可能会出错。你需要的是C#相当于“on next resume next”,否则你将最终复制并粘贴许多代码行的try-catches。
你会如何解决这个问题?
答案 0 :(得分:45)
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 );
答案 1 :(得分:22)
重构为具有明确名称的个别方法:
AdjustFormWidgets();
SetContactTitle(txtTitle.Text);
SeasonCasserole();
每一项都得到适当的保护。
答案 2 :(得分:19)
我会说什么都不做。
是的,没错,没有。你已经清楚地向我发现了两件事:
我说:
如果情况那么糟糕,你会立即清理它。是的,我知道这听起来很糟糕,你可能会开始用错误修正来解决你的问题,但它会让你修复有需要/错误的代码(大量)代码无论它看起来多么糟糕,它实际上都可以正常工作。
一旦你开始赢得战争,你将有更好的处理代码(由于你的所有重构)你将有一个更好的想法为它赢得设计..
尝试将所有这些包装在气泡包装中可能需要很长时间才能完成,您仍然无法更接近解决问题。
答案 3 :(得分:12)
很明显,您在VB.NET中编写代码,实际上有On Error Resume Next,并将其导出到DLL中的C#。其他任何东西都只是一个暴食者 惩罚。
答案 4 :(得分:9)
详细说明,我想我正在质疑这个问题。如果抛出异常,为什么您希望代码只是继续,好像什么都没发生一样?您可能希望在某些情况下出现异常,在这种情况下,您可以围绕该代码编写try-catch块并处理它们,或者出现意外错误,在这种情况下,您应该更喜欢应用程序中止,重试或失败。不要像受伤的僵尸一样呻吟'大脑'。
答案 5 :(得分:7)
这是预处理器有用的事情之一。您可以定义一个吞下异常的宏,然后使用快速脚本将该宏添加到所有行。
所以,如果这是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()块添加到代码中) 。确保它只修改了它应该是困难的行(必须跳过变量声明,循环结构等,你不会破坏构建)。
但是,我认为这些都是可怕的想法,永远不应该这样做,但问的是。 :)
真的,你不应该这样做。您需要找到导致错误的原因并进行修复。吞咽/忽略错误是件坏事,所以我认为正确的答案是“修复错误,不要忽视它!”。 :)
答案 6 :(得分:7)
On Error Resume Next
在C#世界中是一个非常糟糕的主意。也不会添加相当于On Error Resume Next
的实际帮助你。它所做的只是让你处于一个糟糕的状态,这可能会导致更微妙的错误,数据丢失和可能的数据损坏。
但是为了让提问者得到应有的答案,你可以添加一个全局处理程序并检查TargetSite以查看borked的方法。然后你至少可以知道它是什么线。接下来的部分是试图找出如何设置“下一个语句”的方式与调试器的工作方式相同。希望你的筹码在这一点上不会被解开,或者你可以重新创造它,但它肯定值得一试。但是,根据这种方法,代码必须每次都以调试模式运行,以便包含调试符号。
答案 7 :(得分:4)
正如有人提到的,VB允许这样做。在C#中以同样的方式做到这一点怎么样?输入可靠的反射器:
这:
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();
}
}
答案 8 :(得分:3)
重写代码。尝试找到逻辑上相互依赖的语句集,这样如果一个语句失败了,那么下一个语句就没有意义了,如果你想忽略它们的结果,那么将它们放到自己的函数中并将它们放在它们周围。那并继续。
答案 9 :(得分:2)
这可以帮助您识别问题最多的部分。
@ JB King 谢谢你提醒我。 Logging应用程序块具有可用于跟踪事件的Instrumentation事件,您可以在MS Enterprise库文档中找到更多信息。
Using (New InstEvent)
<series of statements>
End Using
此使用中的所有步骤都将追溯到一个日志文件,您可以解析它以查看日志中断的位置(ex被抛出)并识别高级违规者。
重构真的是你最好的选择,但如果你有很多,这可以帮助你找出最严重的罪犯。
答案 10 :(得分:1)
你可以使用goto,但它仍然很混乱。
我实际上想要一段时间的单一语句try-catch。在某些情况下它会很有用,例如添加日志代码或者如果失败则不想中断主程序流。
我怀疑与linq相关的一些功能可以做些什么,但目前还没有时间研究它。如果你可以找到一种方法将一个语句包装成一个匿名函数,那么使用另一个方法在try-catch块中调用它可以工作......但不确定这是否可能。
答案 11 :(得分:1)
捕获应用程序UnhandledException Event中的错误。这样,未处理的异常甚至可以记录为发件人以及开发人员合理的其他信息。
答案 12 :(得分:1)
有趣的问题;太可怕了。
如果可以使用宏,那就太好了。但这是对C#的抨击,所以你可以通过一些预处理器工作或一些外部工具来解决它,将你的行包装在单独的try-catch块中。不确定您是否意味着您不想手动包装它们或者您想要完全避免try-catch 。
搞清楚这一点,我尝试标记每一行并从一个捕获中跳回来,没有太多运气。但是,Christopher uncovered the correct way to do this。有一些interesting additional discussion of this at Dot Net Thoughts和Mike Stall's .NET Blog。
编辑:当然。列出的try-catch
/ switch-goto
解决方案实际上不会编译,因为try
标签超出catch
范围。任何人都知道制作类似这样的内容会缺少什么?
您可以使用编译器预处理步骤自动执行此操作,也可以修改Mike Stall's Inline IL tool以注入一些错误无知。
(Orion Adrian's answer about examining the Exception并尝试设置下一条指令也很有趣。)
总而言之,这似乎是一项有趣且富有启发性的练习。当然,你必须决定在什么时候模拟ON ERROR RESUME NEXT的努力超过了修复代码的努力。 : - )
答案 13 :(得分:1)
为什么不在c#中使用反射?您可以创建一个反映代码的类,并使用行#s作为每个try / catch块中放置内容的提示。这有一些好处:
但是我建议不要这样做,除非你正在接管某些工作的维护,你需要处理异常,以便你可以修复它们。写作可能会很有趣。
答案 14 :(得分:1)
如果您可以让编译器为此代码提供表达式树,那么您可以通过用包装原始语句的新try-catch块替换每个语句来修改该表达式树。这并不像听起来那么牵强;对于LINQ,C#获得了将lambda表达式捕获为表达式树的能力,这些表达式树可以在运行时在用户代码中进行操作。
今天使用.NET 3.5无法实现这种方法 - 如果没有其他原因,只能在System.Linq.Expressions中缺少“try”语句。但是,一旦完成DLR和LINQ表达式树的合并,它在未来的C#版本中可能是可行的。
答案 15 :(得分:0)
您可以查看集成企业库的异常处理组件,以了解如何处理未处理的异常。
如果这是针对ASP.Net应用程序的,那么在Global.asax中有一个名为“Application_Error”的函数,在大多数情况下会被调用,而通常会发生灾难性故障。
答案 16 :(得分:0)
忽略你想避免这样做的所有原因.......
如果只是需要保持行数减少,你可以尝试类似:
int totalMethodCount = xxx; for(int counter = 0; counter < totalMethodCount; counter++) { try { if (counter == 0) WidgetMaker.SetAlignment(57); if (counter == 1) contactForm["Title"] = txtTitle.Text; if (counter == 2) Casserole.Season(true, false); if (counter == 3) ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true; } catch (Exception ex) { // log here } }
但是,如果您尝试重用任何调用结果,则必须密切关注变量范围。
答案 17 :(得分:0)
不幸的是,你可能运气不好。 On Error Resume Next是一个遗留选项,通常非常不鼓励,并且与C#中的知识不相同。
我建议将代码保留在VB中(听起来这是源代码,根据您对OnError ResumeNext的特定请求)以及与C#dll或exe接口,以实现您需要的任何新代码。然后执行重构以使代码安全,并在执行此操作时将此安全代码转换为C#。
答案 18 :(得分:-7)
Hilite每一行,一次一个,'环绕'尝试/捕获。这避免了你提到的复制粘贴