C#的最佳选择“On Error Resume Next”是什么?

如果我为我的C#代码添加空catch块,它是否等同于VB.NET的“On Error Resume Next”语句。

try { C# code; } catch(exception) { } 

我问这个的原因是因为我必须将VB.NET代码转换为C#,旧代码有~200“On Error Resume Next”语句,尽管我在新代码中使用了正确的try {} catch {} ,但有更好的选择吗?

我发现VB程序员经常On Error Resume Next (坏)习惯中使用许多On Error Resume Next语句来填充代码。 我的建议是从没有被抑制的exception开始,看看究竟是什么破坏了。 可能没有你想象的那么多问题。 相反,您可以做的回归测试越多越好; 可能存在一些仅在忽略错误时才起作用的边缘情况。

最终,您需要决定error handling策略,是否在许多try / catch块中优雅展开,或者让错误渗透到顶级处理程序(两种策略都有其用途)。

如果您最终必须禁止某些exception以满足截止日期, 那么至少要记录这些exception,以便下一个处理代码的开发人员不会被空的try/catch烧毁。

虽然有时这是可以接受的,但通常它表示代码气味。 如果您100%确定要吞下已发生的exception,则可以按照您的方式执行此操作,但通常如果抛出exception,您应该执行某些操作

通常,您可以使用设计良好的代码实现相同的结果。 如果您目前遇到特定错误,请将其添加到您的问题中,但如果您只是出于好奇而不是,那么就没有相应的问题,这是一件好事。

您需要逐个分析On Error Resume Next语句,看看它们的用途是什么。 有些可能只是草率的代码,但有正确的原因在Visual Basic 6.0代码中On Error Resume Next

为什么在Visual Basic 6.0代码中使用On Error Resume Next一些示例:

  • 检查Visual Basic 6.0集合中是否存在给定键。 执行此操作的唯一方法是按键访问元素,并处理在密钥不存在时引发的错误。 转换为.NET时,可以通过检查密钥是否存在来替换它。

  • 将字符串解析为整数。 在.NET中,您可以使用TryParse 。

不,这不一样。

使用On Error Resume Next时,如果发生错误,VB将跳到下一行。 使用try / catch,如果发生错误(exception),执行将跳转到catch块。

虽然On Error Resume Next肯定比合法使用的滥用更多,但有些地方甚至在VB.NET中也会有所帮助。

考虑一个程序,它为大量Excel属性分配值,例如所有打印机参数的默认值 – Excel中有大量的打印机参数。 更高版本的Excel可能具有早期版本不支持的属性,并且要弄清楚每个版本支持哪些属性并非易事。 如果属性存在,程序应分配值,但如果使用旧版本的Excel,则忽略该属性。

使用VB.NET执行此操作的“正确”方法是确定每个版本的Excel支持哪些打印机属性,读取正在使用的版本,并仅分配在该版本中实现的属性。 这需要大量的研究和一些代码,所有这些都没有什么好处。 On Error Resume Next将是一个更实用的解决方案。

而且,不幸的是,我现在正面临着这个问题。 我要尝试的解决方法是编写一个子程序,它只将一个值分配给另一个,忽略错误。 我将这个子路由称为每个赋值语句。 不是太明显,但也不是那么好。

使用“On Error Resume Next”不是error handling的好主意(当然,这是我个人的看法,但似乎大多数开发人员都同意我的意见)。 正如其他人在之前的post中建议的那样,使用Try...Catch...Finally (无论是在VB.NET还是C#中)。

这是一个非常智能的error handling选项,但它也允许你对错误(空的catch块)不做任何事情:)我建议你在单独的Try...Catch Block放入每一行代码(可能会导致错误) Try...Catch Block ,这样你就有机会在发生错误时做任何你想做的事情。 快乐的编码家伙:)

“On Error Resume Next”允许“内联error handling”,这是VB中的专家级error handling。 这个概念是逐行处理错误,要么根据错误执行操作,要么在有益时忽略错误 – 但是在编写错误的序列中运行代码而不使用代码跳转。

不幸的是,许多新手使用“On Error Resume Next”通过忽略所有错误来隐藏他们缺乏能力或者使用他们的应用程序的懒惰。 Try/catch是块级error handling,在.NET之前的世界中,它是设计和实现的中间层。

VB.NET中“On Error Resume Next”的问题在于它在执行代码的每一行上加载了错误对象,因此比try/catch慢。 我有点担心这个论坛检查并提升了一个愚蠢的答案声称使用On Error Resume Next是一个坏习惯和代码垃圾。 这是一个C#论坛; C#程序员真的应该用另一种他们不熟悉的语言拍摄吗?

https://msdn.microsoft.com/en-us/library/aa242093(v=vs.60).aspx

据说没有真正VB经验的中级C#程序员不应该试图保持C#的function,因为他们对另一种“Microsoft Net”语言的怪异蔑视而function有限,请考虑以下代码:

 //-Pull xml from file and dynamically create a dataset. string strXML = File.ReadAllText(@"SomeFilePath.xml"); StringReader sr = new StringReader(strXML); DataSet dsXML = new DataSet(); dsXML.ReadXml(sr); string str1 = dsXML.Tables["Table1"].Rows[0]["Field1"].ToString(); string str2 = dsXML.Tables["Table2"].Rows[0]["Field2"].ToStrin(); string str3 = dsXML.Tables["Table3"].Rows[0]["Field3"].ToStrin(); string str4 = dsXML.Tables["Table4"].Rows[0]["Field4"].ToString(); string str5 = dsXML.Tables["Table5"].Rows[0]["Field5"].ToString(); 

如果xml通常具有Field3的值,但有时不具有; 我将得到一个恼人的错误,表不包含该字段。 如果没有,我可以少关心,因为它不是必需的数据。 在这种情况下,ON Error Resume Next将允许我忽略错误,我不必围绕每行代码设置变量,检查是否存在与Contains方法的表,行和列组合。 这是一个小例子; 我可能从大文件中提取数千个表,列,行组合。 此外,假设必须以这种方式填充字符串变量。 这是未处理的代码,会有麻烦。

考虑一个VB.NET和ON错误恢复下一个实现:

 On Error Resume Next 'Pull Xml from file And dynamically create a dataset. Dim strXML As String = File.ReadAllText("SomeFilePath.xml") Dim srXmL As StringReader = New StringReader(strXML) Dim dsXML As DataSet = New DataSet() dsXML.ReadXml(srXmL) 'Any error above will kill processing. I can ignore the first two errors and only need to worry about dataset loading the XML. If Err.Number <> 0 Then MsgBox(Err.Number & Space(1) & Err.Description) Exit Sub 'Or Function End If Dim str1 As String = dsXML.Tables("Table1").Rows(1)("Field1").ToString() Dim str2 As String = dsXML.Tables("Table2").Rows(2)("Field2").ToString() Dim str3 As String = dsXML.Tables("Table3").Rows(3)("Field3").ToString() Dim str4 As String = dsXML.Tables("Table4").Rows(4)("Field4").ToString() 

在上面的代码中,只需要处理一个可能的错误条件; 即使在处理第三个错误之前有两个错误。 RAD开发需要On Error Resume Next。 C#是我选择的语言,但由于种种原因,它不像VB语言那么多。 我希望所有程序员都意识到几种主要语言(即C)只运行并且不会停止对未处理错误的执行; 在他们认为必要的地方检查他们是开发人员的工作。 On Error Resume Next是微软世界中最接近该范例的东西。

幸运的是,.NET确实提供了许多先进的选择来处理这些情况; 我没收到包含物。 因此,在C#中,您必须提高语言的知识水平,并根据C#语言规范正确地解决这些问题。 考虑一个处理大块重复代码行的解决方案,这些代码行可能包含恼人的丢弃错误:

 try { if (!File.Exists(@"SomeFilePath.xml")) { throw new Exception("XML File Was Not Found!"); } string strXML = File.ReadAllText(@"SomeFilePath.xml"); StringReader sr = new StringReader(strXML); DataSet dsXML = new DataSet(); dsXML.ReadXml(sr); Func GetFieldValue = (t, f, x) => (dsXML.Tables[t].Columns.Contains(f) && dsXML.Tables[t].Rows.Count >= x + 1) ? dsXML.Tables[t].Rows[x][f].ToString() : ""; //-Load data from dynamically created dataset into strings. string str1 = GetFieldValue("Table1", "Field1", 0); string str2 = GetFieldValue("Table2", "Field2", 0); string str3 = GetFieldValue("Table3", "Field3", 0); //-And so on. } catch (Exception ex) { Debug.WriteLine(ex.Message); } 

虽然在try / catch块中,lambda函数正在检查是否存在从xml动态填充的数据集中提取的每个表,行,列组合。 这可以逐行检查,但需要大量多余的代码(这里我们有相同数量的执行代码,但编写的代码要少得多)。 不幸的是,这可能被认为是“一线function”的另一种不良做法。 我在lambdas和匿名函数的情况下打破了这个规则。

由于.NET提供了很多方法来检查对象的状态; On Error Resume Next对于VB专家来说并不像.NET之前那样重要,但仍然很好用。 特别是当你编写一些浪费时间来编写快速和脏的代码时。 Java转换为C#; 加入微软世界并停止假装,如果10000名中级Java和C#程序员说出来,那么它必须是真实的,因为如果一个顶级Microsoft Guru(例如创建VB语言和.NET的任何一个)显然与你相矛盾他们开发.NET本身,这是假的,你看起来很愚蠢。 我想要用C#和VB和F#以及我需要使用的任何其他语言获得的所有function。 C#是优雅的,但VB更加发展,因为它的任期更长,但它们都做“相同的事情”并使用相同的对象。 要好好学习它们,或者在比较对话中拒绝评论; 对于我们这些自九十年代中期以来一直使用微软技术的人来说,这是令人作呕的。

正确的.NET替换“on next resume next”是使用Try___方法。 在Visual Basic 6.0中,要查明集合中是否存在密钥,必须手动搜索集合(非常慢),否则尝试对其进行索引并捕获发生的任何错误(如果不存在)。 在VB.NET中,Dictionary对象(它是旧Collection的改进版本)支持TryGetValue方法,该方法将指示尝试获取值是否成功,如果不成功则不会导致错误。 许多其他.NET对象支持类似的function。 有一些方法应该具有“尝试”等价物但不具备(例如, Control.BeginInvoke ),但是它们中足够少的将它们单独包装在Try/Catch中并不是太繁重。

我碰巧认为那些发明了“On Error Resume Next”的人在创建它时确实有一些想法。 你的问题的答案是否定的,在C#中没有与这个结构相当的东西。 我们在C#和.Net中有很多function,这些function非常渴望得到关注和关注,一段时间之后它会让人厌倦,以满足每个人的“特殊行为”。 当几乎所有东西都能抛出exception时,这个词本身就会失去它的含义。 你是在一个迭代中,如果成千上万的项目碰巧是特殊的,你该怎么办? 继续下一个可能是一个方便的答案。

正如@Tim Medora所说,你必须努力避免在编码时使用这种方法。 但是,在某些情况下它很有用,并且可以模拟这种行为。 这是一个function和使用它的一个例子。 (注意一些代码元素是使用C#6编写的)

  ///  /// Execute each of the specified action, and if the action is failed, go and executes the next action. ///  /// The actions. public static void OnErrorResumeNext(params Action[] actions) { OnErrorResumeNext(actions: actions, returnExceptions: false); } ///  /// Execute each of the specified action, and if the action is failed go and executes the next action. ///  /// if set to true return list of exceptions that were thrown by the actions that were executed. /// if set to true and  is also true, put null value in the returned list of exceptions for each action that did not threw an exception. /// The actions. /// List of exceptions that were thrown when executing the actions. ///  /// If you set  to true, it is possible to get exception thrown when trying to add exception to the list. /// Note that this exception is not handled! ///  public static Exception[] OnErrorResumeNext(bool returnExceptions = false, bool putNullWhenNoExceptionIsThrown = false, params Action[] actions) { var exceptions = returnExceptions ? new Collections.GenericArrayList() : null; foreach (var action in actions) { Exception exp = null; try { action.Invoke(); } catch (Exception ex) { if(returnExceptions) { exp = ex; } } if (exp != null || putNullWhenNoExceptionIsThrown) { exceptions.Add(exp); } } return exceptions?.ToArray(); } 

示例,而不是:

  var a = 19; var b = 0; var d = 0; try { a = a / b; } catch { } try { d = a + 5 / b; } catch { } try { d = (a + 5) / (b + 1); } catch { } 

您可以:

  var a = 19; var b = 0; var d = 0; OnErrorResumeNext( () =>{a = a / b;}, () =>{d = a + 5 / b;}, () =>{d = (a + 5) / (b + 1);} ); 

我是VB6的老帽子。 首先是一个简短的教训

有理由使用On Error Resume Next。 主要是为了可读性。 在VB6中,您有两种方法来实现错误捕获。 您可以像这样使用“内联”On Error Resume Next。

 On Error Resume Next  If Err.Number <> 0 Then  Err.Clear() End If 

或者,您可能会看到:

 Sub DoSomething On Error Goto Handler1  On Error Goto Handler2  Exit Sub Handler1:  Resume Next Handler2:  Resume Next End Sub 

但在旧的VB6代码中你可能也会看到这个……

 Sub PerformThis On Error Resume Next End Sub 

无论将这些案例转换为Try Catch都是非常直接的…如果您需要下沉错误,请使用快速“内联”查看错误恢复接下来就这样做..

 try { _objectinfo.Add(_object.attribute1); } catch (Exception _e) { } 

您还可以通过将代码封装到子例程中来将try catch提升到调用例程…因此,如果您需要接收整个子例程,请执行此操作…

 try { PerformAction(); } catch (Exception _e) { } 

在PerformAction()子例程在代码顶部包含On Error Resume Next的情况下执行此操作,在调用子例程中使用Try Catch

祝好运…