【问题标题】:What is the best alternative "On Error Resume Next" for C#?C# 的最佳替代“On Error Resume Next”是什么?
【发布时间】:2026-01-22 21:40:01
【问题描述】:

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

try
{
    C# code;
}

catch(exception)
{
}

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

【问题讨论】:

  • 缺少On Error Resume Next 的替代品不仅仅是无意的疏忽……您为什么可能需要这个?如果您解释您的想法背后的动机,我确信这里有人可以为您提供更好的解决方案。
  • @MarkJ:因为即使他将代码保留为 VB.NET,仍然On Error Goto Next 替换为更结构化的异常处理(或一个都没有)。
  • @Cody 是一种替代错误处理的改进,但你必须评估它需要多长时间(花费多少)以及代码是否需要大量修改。如果代码有效且不需要更改,则可能有更好的时间来处理。
  • @MarkJ:很公平。我不同意你的观点,我只是提供了我认为对另一方有说服力的论据。这是您必须做出的设计决策之一。我是坚持使用碰巧可以工作的草率代码,还是花时间改进它以获得长期利益。我假设进行转换的原因是因为代码没有按原样完全正确地工作。其他情况可能会有所不同,您的建议值得考虑。
  • @CodyGray:我可以想出许多想要resume next 功能的正当理由。假设您正在删除一堆文件,但知道其中一些文件可能不再存在,如果您遗漏了一个文件(例如,如果它正在使用中),它可能并不那么重要。在这种情况下,为什么每个操作都需要try...catch

标签: c# vb.net error-handling vb.net-to-c#


【解决方案1】:

我发现 VB 程序员出于(坏)习惯经常在代码中乱扔很多 On Error Resume Next 语句。我的建议是从 no 被抑制的异常开始,然后看看到底发生了什么。问题可能没有你想象的那么多。相反,你能做的回归测试越多越好;可能有一些边缘情况只有在忽略错误时才有效。

最终,您需要决定错误处理策略,是在许多 try/catch 块中优雅地展开,还是让错误渗透到*处理程序(这两种策略都有其用途)。

如果您最终不得不抑制某些异常以赶上最后期限,至少记录这些异常,以便下一个处理您的代码的开发人员不会被空的 @987654322 烧毁@。

【讨论】:

    【解决方案2】:

    虽然有时这是可以接受的,但通常它表示代码异味。如果您 100% 确定要吞下已发生的异常,您可以按照自己的方式进行,但通常如果抛出异常,您应该某事 .

    通常,您可以通过精心设计的代码实现相同的结果。如果您当前遇到特定错误,请将其添加到您的问题中,但如果您只是出于好奇而询问,则没有等效错误,这是一件好事。

    【讨论】:

      【解决方案3】:

      尽管On Error Resume Next 被滥用的次数肯定多于合法使用的次数,但即使在 VB.NET 中也有一些地方会有所帮助。

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

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

      不幸的是,我现在正面临这个问题。我要尝试的解决方法是编写一个子例程,它只将一个值分配给另一个值,而忽略错误。我将调用此子路由来代替每个赋值语句。不是太糟糕,但也不是那么好。

      【讨论】:

        【解决方案4】:

        不,不一样。

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

        【讨论】:

        • 我想你可以包装每一个可能在其自己的 try/empty catch 中中断的语句以获得类似的效果,但这将是一些邪恶的代码。
        • @Tim:呵呵,这么久我就不需要维护那个代码了!
        • 宾果游戏。没错。
        【解决方案5】:

        你需要一一分析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 一样糟糕。 On Error Resume Next 存在是有原因的,但这将与其他语句一起使用 - IFscatch 只是一种错误类型,On Error GoTo 0 恢复错误引发,而不仅仅是跳过它们。
        • @Mike:我不太确定你在这里想说什么。乔的回答明确说明您将“处理如果密钥不存在时引发的错误”。我几乎只在 VB 6 中使用(d)On Error Resume Next 来实现我自己的错误处理例程。我想我们都在说同样的话。如果您明智地使用它,该语句在 VB 6 中占有一席之地,但在 VB.NET 中则完全没有(因为它引入了优越的 try/catch 语法)。
        • @Cody Gray - 同意。大约 10 年前,我在一个大型产品团队工作,标准策略是在我们所有的 VB 代码中包含 On Error Resume Next。但是,如果您的代码没有在例程执行时不断测试错误条件,那么您将在代码审查中受到严厉批评。它导致了一些极其冗长的代码,但可以编写处理异常情况的可靠代码。
        • @Tim:绝对最荒谬的情况是在显示打开/保存通用对话框时必须这样做。如果用户取消,它会引发错误,您必须适当地捕获和处理。我从来不知道为什么一个空的 FileName 值是一个不足的指标......
        • @Cody Gray - 我想说的是基本相同的事情......只是想扩展如何处理 VB 中的错误。
        【解决方案6】:

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

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

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

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

        据说没有真正 VB 经验的中级 C# 程序员不应该因为他们对另一种“Microsoft Net”语言的奇怪蔑视而试图让 C# 变得愚蠢和功能有限,请考虑以下代码:

        //-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"].ToString();
        string str3 = dsXML.Tables["Table3"].Rows[0]["Field3"].ToString();
        string str4 = dsXML.Tables["Table4"].Rows[0]["Field4"].ToString();
        string str5 = dsXML.Tables["Table5"].Rows[0]["Field5"].ToString();
        

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

        考虑一个 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 那样是一种 RAD 语言。我希望所有程序员都意识到几种主要语言(即 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<string, string, int, string> 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 动态填充的数据集中提取的每个表、行、列组合是否存在。这可以逐行检查,但需要大量多余的代码(这里我们有相同数量的执行代码,但要维护的书面代码要少得多)。不幸的是,这可能被认为是“单线功能”的另一种不良做法。在 lambdas 和匿名函数的情况下,我打破了这条规则。

        由于 .NET 提供了很多方法来检查对象的状态; On Error Resume Next 对 VB 专家来说并不像在 .NET 之前那样重要,但仍然很好用;尤其是当您编写的代码会浪费时间而不是快速和肮脏的代码时。对你来说,Java 转换为 C#;加入微软世界,不要再假装如果 10000 名中级 Java 和 C# 程序员都这么说,那一定是真的,因为如果一位*微软大师(例如任何一位创建 VB 语言和 .NET 的人)显然在他们开发 .NET 本身,这是错误的,你看起来很愚蠢。我想要在 C#、VB 和 F# 以及我需要使用的任何其他语言中获得的所有功能。 C# 很优雅,但 VB 更进化,因为它的任期更长,但它们都做“相同的事情”并使用相同的对象。把它们都学好,或者请不要在比较对话中评论任何一个;对于我们这些从九十年代中期就在高水平使用微软技术的人来说,这真是令人作呕。

        【讨论】:

          【解决方案7】:

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

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

          【讨论】:

            【解决方案8】:

            “on error resume next”的正确 .NET 替代方法是使用 Try___ 方法。在 Visual Basic 6.0 中,要查明集合中是否存在键,必须手动搜索集合(非常慢),或者尝试索引它并捕获发生的任何错误(如果它不存在)。在 VB.NET 中,Dictionary 对象(它是旧 Collection 的改进版本)支持TryGetValue 方法,该方法将指示获取值的尝试是否成功,如果不成功则不会导致错误。许多其他 .NET 对象支持类似的功能。有一些方法应该具有“尝试”等效项,但没有(例如,Control.BeginInvoke),但它们中的数量很少,因此将它们单独包装在 Try/Catch 中并不太麻烦。

            【讨论】:

              【解决方案9】:

              我碰巧认为那些发明“On Error Resume Next”的人在创建它时确实有一些想法。 您的问题的答案是否定的,在 C# 中没有与此构造等效的东西。 我们在 C# 和 .Net 中有很多非常需要关心和关注的函数,但为了迎合每个人的“异常行为”,一段时间后就会变得很累。当几乎所有东西都可以抛出异常时,这个词本身就失去了它的意义。 你在一个迭代中,如果数以万计的数以万计的项目恰好是例外的,你应该怎么做? Resume Next 可能是方便的答案之一。

              【讨论】:

                【解决方案10】:

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

                    /// <summary>
                    /// Execute each of the specified action, and if the action is failed, go and executes the next action.
                    /// </summary>
                    /// <param name="actions">The actions.</param>
                    public static void OnErrorResumeNext(params Action[] actions)
                    {
                        OnErrorResumeNext(actions: actions, returnExceptions: false);
                    }
                
                    /// <summary>
                    /// Execute each of the specified action, and if the action is failed go and executes the next action.
                    /// </summary>
                    /// <param name="returnExceptions">if set to <c>true</c> return list of exceptions that were thrown by the actions that were executed.</param>
                    /// <param name="putNullWhenNoExceptionIsThrown">if set to <c>true</c> and <paramref name="returnExceptions"/> is also <c>true</c>, put <c>null</c> value in the returned list of exceptions for each action that did not threw an exception.</param>
                    /// <param name="actions">The actions.</param>
                    /// <returns>List of exceptions that were thrown when executing the actions.</returns>
                    /// <remarks>
                    /// If you set <paramref name="returnExceptions"/> to <c>true</c>, it is possible to get exception thrown when trying to add exception to the list. 
                    /// Note that this exception is not handled!
                    /// </remarks>
                    public static Exception[] OnErrorResumeNext(bool returnExceptions = false, bool putNullWhenNoExceptionIsThrown = false, params Action[] actions)
                    {
                        var exceptions = returnExceptions ? new ArrayList() : 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 (Exception[])(exceptions?.ToArray(typeof(Exception)));
                    } 
                

                示例,而不是:

                        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);}
                            );
                

                【讨论】:

                  【解决方案11】:

                  我是 VB6 的老手。首先是简短的课程...

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

                  On Error Resume Next
                  <something that may throw an error>
                  If Err.Number <> 0 Then
                     <do something about this specific line of code>
                     Err.Clear()
                  End If
                  

                  或者,您可能会看到:

                  Sub DoSomething
                  
                     On Error Goto Handler1
                     <do something that causes an error>
                  
                     On Error Goto Handler2
                     <do something that may cause an error>
                  
                     Exit Sub
                  
                     Handler1:
                     <log error or something>
                     Resume Next
                  
                     Handler2:
                     <log error or something>
                     Resume Next
                  
                  End Sub  
                  

                  但在旧的 VB6 代码中,您可能还会看到这个...

                  Sub PerformThis
                  On Error Resume Next
                  
                  End Sub
                  

                  尽管将这些案例转换为 Try Catch 非常简单...如果您需要解决错误,请使用快速“内联”查看 On Error Resume Next 只需执行此操作..

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

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

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

                  如果 PerformAction() 子例程在代码顶部包含 On Error Resume Next,请在调用子例程中使用 Try Catch

                  祝你好运……

                  【讨论】:

                    最近更新 更多