我想念C#中Visual Basic的“On Error Resume Next”。 我现在该如何处理错误?

在Visual Basic中,我在程序的头部编写了On Error Resume Next ,并在整个项目中抑制了错误。

在C#中我非常想念这个function。 对于每个程序而言,通常的try-catch处理不仅非常耗时,而且会带来不希望的效果。 如果遇到错误,即使已处理,代码也不会从发生的位置继续 。 使用On Error Resume Next ,代码从错误点继续,仅跳过导致错误的函数调用。

我还没有深入参与C#,但也许C#中存在比原始try-catch更好的error handling。

我还想知道发生错误的模块或函数名称以及错误消息中的行号。 到目前为止, Exception类没有提供这些function。 任何想法(当然,托管,不涉及我自己的应用程序上的任何流程类)?

你如何处理大项目中的错误? 我希望我不必为每个方法添加try-catch 。 不知何故C#抛出了许多错误 – 这似乎是该语言的典型。

我发现我的解决方案可以解决我的几个问题:

 public partial class Form1 : Form { public Form1() { InitializeComponent(); } [STAThread] static void Main() { Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); //setup global error handler Application.Run(new Form1()); } private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { MessageBox.Show("Unhandled exception: " + e.Exception.ToString()); //get all error information with line and procedure call Environment.Exit(e.Exception.GetHashCode()); //return the error number to the system and exit the application } private void button1_Click(object sender, EventArgs e) { string s = ""; s.Substring(1, 5); //Produce an error } } 

在错误之后继续,好像什么都没发生是一种可怕的编程方式。

无法计算出帐户的新余额? 没关系,让我们把它存储为0.没有人会知道,对吧?

try / catch块实际上应该是相对罕见的,因为你可以真正从中恢复的错误相对较少。 通常,您应该在某个逻辑操作的顶部有一个try / catch块,这样如果它失败,您可以通知用户并继续执行其他完全独立的操作 – 或者完全终止应用程序,具体取决于您的应用程序类型写作。 (Web应用程序在这里是一个很好的例子:您可以使请求失败,希望注意您没有令人讨厌的持久性副作用,并继续处理其他请求。)

如果有合理地预期错误的地方可以从中恢复,请捕获这些特定exception并适当地处理它们(例如,如果写入数据库失败,则回写到写入文件)。 同样,这些相对较少且相差甚远。 如果您发现自己在每个方法(甚至每个类)中编写了一个try / catch块,那么您可能不恰当地处理exception。

我还想要出现错误的模块或函数名称以及错误消息中的行号。 Exception类不提供我所体验到的function。

是的,它确实。 堆栈跟踪显示堆栈中每个帧的类型,方法和行号(如果可用)…当然还有(希望有用的)消息。 哦,如果一个失败是由另一个引起的,那么也可能是一个嵌套exception。

不知怎的,C#总是在执行时抛出许多错误,这是典型的语言。

不,这只是暗示你做错了。

没有。

作为一名前VB程序员,请允许我向您保证:这是有史以来最糟糕,最滥用的function。 以下是这个想法:

  1. 编写没有错误的代码……除非发生实际上有问题的事情。 这可能涉及在您做事之前检查您的假设 ; 太棒了:做那个
  2. 只抓住你期待的问题; 吞下所有错误只是要求大量的问题

正如Jon已经指出的那样,实际上很少需要在整个地方进行exception处理。 通常你只是让exception泡到更高的调用者,因为发生了一些不好的事情 。 当我try ,更常见的是try / finally (不是try / catch ) – usinglock (etc)是为了方便起见的特殊情况。

实际上,exception是例外,它们不会一直发生。 当它们发生时,你想知道它们发生了,要么处理它们,要么关闭你的过程。 大多数时候让exception处理不当会导致非常意外的结果。

不,你不能。 这在C#中是不可能的(并且不应该是任何其他语言)。

VB中的真正用途是在代码的某些部分进行error handling,就像try / catch 。 启用它,检查Err.Number <> 0 ,完成工作并使用On Error GoTo 0恢复错误流程或重定向到跟随不同路径的标签以处理错误或继续执行On Error GoTo someErrorCase: .

你必须学会​​单独编程或与没有正确编程的人编程。 忽略错误是一个坏习惯,更重要的是,只需遵循代码即可。 毕竟,错误是可能的。

相信我。 我是一名VB程序员,当我停下来阅读最佳实践时,它很有启发性。

只是添加一些,尝试使用Option Explicit ,它可能听起来更多的工作声明所有变量,但它会让你更自信的代码,因为类型检查将限制一些常见的错误。

此外,C#exception非常有用,并且包含您可能需要的所有信息。 如果您没有遇到exception本身的问题,只需打开它并查看其内部exception(我发现在Web开发时我总是看到内部exception,因为所有代码都处于更高级别)。

你一直在使用那个VBfunction错了,你很幸运,你不能像在C#中那样使用它。

在VB中使用该function时,您应该在每次可能导致错误的操作后检查错误状态。 如果使用得当,它的代码不会少于每次操作可能导致错误的try...catch块。

因此,如果您认为必须在C#中执行更多error handling,那么之前您的error handling过少。

“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慢。

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 Dim strXML As String = File.ReadAllText("SomeNonExistentFileCausingAnErrorCondition.xml") If String.IsNullOrEmpty(strXML) Then strXML = strSomeOtherValidXmlThatIUseWhenTheFileIsEmpty End If Dim srXmL As StringReader = New StringReader(strXML) Dim dsXML As DataSet = New DataSet() dsXML.ReadXml(srXmL) If Err.Number <> 0 Then MsgBox(Err.Number & Space(1) & Err.Description) Exit Sub 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() 

在上面的代码中,只需要处理一个可能的错误条件; 即使加载文件时出错也是如此。 On Error Resume Next实际上允许我按预期恢复,这允许我检查字符串条件并使用我的备用字符串(我很清楚我也可以检查文件的存在并避免文件错误但是如果它是一个没有任何内容的好文件,strXML将是一个空字符串)。 处理了对其余代码至关重要的错误,并且退出了该方法,因为加载的数据集对于超出它的其余处理是最重要的(如果需要,可以通过忽略任何错误来执行处理)。 我忽略它可能会忽略文件错误,或者我可以检查错误情况并记录它。

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之前那样重要,但仍然很好用。 特别是当你编写一些浪费时间来编写快速和脏的代码时。 在专家级别上曾经使用VB的人都不会声称On Error Resume Next(内联error handling)是有史以来添加到语言中的最糟糕的function。 然而,它被新手广泛滥用。