vbs 用On Error Resume Next跳过错误,但又想记录错误信息怎么办?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vbs 用On Error Resume Next跳过错误,但又想记录错误信息怎么办?相关的知识,希望对你有一定的参考价值。
vbs 用On Error Resume Next跳过错误,但又想记录错误信息怎么办?能否将错误信息保存到一个文本中,方便查看?
参考技术A 代码如下:On Error Resume NextErr.Raise 6 '例如产生溢出错误(6)。
If Err.Number<>0 then
Set fso=WScript.CreateObject("scripting.filesystemobject")
Set fs=fso.CreateTextFile("123.txt")
fs.Write "Error # " & CStr(Err.Number) & " " & Err.Description
End if
Err.Clear '清除错误。
我想念 C# 中的 Visual Basic “On Error Resume Next”。我现在应该如何处理错误?
【中文标题】我想念 C# 中的 Visual Basic “On Error Resume Next”。我现在应该如何处理错误?【英文标题】:I miss Visual Basic's "On Error Resume Next" in C#. How should I be handing errors now? 【发布时间】:2012-07-20 17:10:37 【问题描述】:在 Visual Basic 中,我只在我的程序头部写了 On Error Resume Next
并且在整个项目中都抑制了错误。
在 C# 中,我非常怀念这个特性。对每个单独的程序进行通常的try-catch
处理不仅非常耗时,而且会带来不良影响。如果遇到错误,即使已处理,代码也不会继续从它发生的那一点开始。使用On Error Resume Next
,代码从错误点继续,只跳过导致错误的函数调用。
我还没有深入参与 C#,但也许 C# 中存在比原始 try-catch
更好的错误处理。
我还想知道发生错误的模块或函数名称以及错误消息中的行号。据我所知,Exception
类不提供这些功能。有什么想法(当然是管理,而不涉及我自己的应用程序中的任何流程类)?
您如何处理大型项目中的错误?我希望我不必为每个方法添加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
【问题讨论】:
异常是有意义的。忽略它们就是混乱。 这可能是一个不好的迹象,表明您需要全局 try/catch。您的大多数代码不应产生错误,只有在极少数情况下您才会抛出异常。 @feedwall:不,您应该找到这些错误并修复它们。您遇到的情况非典型。您可能想开始编写单元测试... 这其实是个好问题。它表明 OP 目前正在做各种错误的事情,但它非常清楚地解释了情况,并且答案应该能够给处于相同情况的任何人带来启发。一个好的问题表明一个糟糕的程序员比一个好的程序员的坏问题更有用,IMO :) 如果“废话”只是被跳过了,正如你所说,那你为什么要打电话呢? feedwall,我直截了当地告诉你 - 从事过你描述的项目,你的应用程序没有运行良好。数据已损坏。你很幸运没有因此而遭受任何毁灭性的失败(你知道的)。在这里相信我们 - 如果没有该指令,您将制作出更多更高质量的作品。 【参考方案1】:实际上,异常就是异常,它们不会一直发生。当它们确实发生时,您想知道它们发生了,然后处理它们或关闭您的流程。大多数情况下,不处理异常会导致非常意想不到的结果。
【讨论】:
【参考方案2】:在错误之后继续,好像什么都没发生一样是一种可怕的编程方式。
无法计算出账户的新余额?没关系,我们把它存储为 0。没有人会知道,对吧?
try
/catch
块实际上应该相对较少,因为您可以真正恢复的错误相对较少。通常,您应该在某个逻辑操作的顶部有一个 try/catch 块,这样如果它失败了,您可以通知用户并继续其他完全独立的操作 - 或完全终止应用程序,具体取决于您的应用程序类型写作。 (Web 应用程序就是一个很好的例子:您可以使请求失败,希望注意不要产生令人讨厌的持久副作用,并继续处理其他请求。)
在您合理地期望可以从错误中恢复的地方,捕获这些特定异常并适当地处理它们(例如,如果写入数据库失败,则回退到写入文件)。同样,这些相对较少而且相距甚远。如果您发现自己在每个方法(甚至每个类)中都编写了 try
/catch
块,那么您可能处理异常不当。
我还想知道发生错误的模块或函数名称以及错误消息中的行号。据我所知,Exception 类没有提供这些功能。
是的。堆栈跟踪显示堆栈中每个帧的类型、方法和行号(如果可用)......当然还有一个(希望有用的)消息。哦,如果一个故障是由另一个故障引起的,也可能是嵌套异常。
不知何故,C# 总是在执行时抛出许多错误,这是语言的典型特征。
不,这只是表明你做错了。
【讨论】:
查看引发的异常 @feedwall 的StackTrace
和 Message
属性(如果从调试器运行,Visual Studio 会显示该属性)。徘徊 - 在子类异常的其他属性中通常有有用的信息,InnerException
有时会包含嵌套异常。
@feedwall:您不应该考虑异常 numbers。使用异常type,结合消息——当然还有堆栈跟踪。
@feedwall:“也许我可以使用 SendKeys 以某种方式自动关闭抛出的错误,然后为用户按下“继续”按钮,但我不确定我会如何做到这一点。”不不不! 请阅读此处的所有答案 - 您绝对应该不想要抑制错误并继续这样做。您的用户将不会欣赏您的应用用坏数据覆盖好数据,因为您决定忽略坏代码。
无意粗鲁,@feedwall,我只想说:你的提议是非常非常错误的。不要这样做。你很沮丧,你有点猛烈抨击。趁着周末走开。
哦,他不是在抨击我们,Jon - 很抱歉暗示这一点。但是,当我读到类似“也许我可以使用 SendKeys 以某种方式自动关闭抛出的错误并按“继续” 之类的建议解决方案时,我想象一个人在他最后的耐心线上,正在长溃疡和大约把他的笔记本电脑扔出窗外。我去过那里,但它不健康。最好走开。【参考方案3】:
没有。
作为一名前 VB 程序员,请让我向您保证:这是有史以来添加到任何语言中最糟糕和最受滥用的功能。下面是这个想法:
-
编写不会出错的代码...除非发生了实际上是问题的事情。这可能涉及在您做事之前检查您的假设;太棒了:这样做
只捕获您预期的问题;吞下所有错误只是在自找麻烦
正如 Jon 已经指出的,实际上很少需要到处处理异常。通常你只是让一个异常冒泡到更高的调用者,因为刚刚发生了一些不好的事情。而当我确实拥有try
时,更常见的是try
/finally
(不是try
/catch
)——using
和lock
(等等)为方便起见,将其作为特例。
【讨论】:
【参考方案4】:不,你不能。这在 C# 中是不可能的(也不应该在任何其他语言中)。
这个在 VB 中的真正用途是在代码的某些部分进行错误处理,就像 try / catch
。您启用它,检查Err.Number <> 0
,完成您的工作并使用On Error GoTo 0
恢复错误流,或重定向到遵循不同路径的标签以处理错误或继续执行On Error GoTo someErrorCase:
。
您一定已经学会了独自编程或与不正确的人一起编程。忽略错误是一个坏习惯,不仅如此,仅仅遵循代码是一件可怕的事情。毕竟,错误是可能的。
相信我。我是一名 VB 程序员,当我停下来阅读最佳实践时,它很有启发性。
只是补充一些,也尝试使用Option Explicit
,这听起来可能需要声明所有变量,但它会让你对代码更有信心,因为类型检查会限制一些常见的错误。
此外,C# 异常非常有用,并且包含您可能想要的所有信息。如果您没有遇到异常本身的问题,只需打开它并查看其内部异常(我发现我在为 Web 开发时总是查看内部异常,因为所有代码都处于更高级别)。
【讨论】:
@Michael Petrotta 感谢您纠正我的错别字和拼写。 +1 用于实际解释该功能是如何演变的。我永远不会想到实际上有一种理智的方式来使用它。【参考方案5】:你一直在错误地使用那个 VB 功能,你很幸运不能像在 C# 中那样使用它。
在 VB 中使用该功能时,您应该在每次可能导致错误的操作后检查错误状态。如果使用得当,它的代码不会比在每个可能导致错误的操作周围都有 try...catch
块少。
因此,如果您认为必须在 C# 中进行更多错误处理,那么您之前所做的错误处理太少了。
【讨论】:
【参考方案6】:“On Error Resume Next”允许“内联错误处理”,这是 VB 中的专家级错误处理。这个概念是逐行处理错误,或者根据错误执行操作,或者在有益时忽略错误 - 但按照编写代码的顺序运行代码而不使用代码跳转。
不幸的是,许多新手使用“On Error Resume Next”通过忽略所有错误来向使用他们的应用程序的人隐藏他们的能力不足或懒惰。 Try/catch 是块级错误处理,在 .NET 之前的世界中,它在设计和实现上是中间的。
VB.NET 中“On Error Resume Next”的问题在于,它在执行代码的每一行都加载了 err 对象,因此比 try/catch 慢。
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"].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 将允许我忽略错误,并且我不必围绕每一行代码编写代码,设置变量检查表、行和列组合是否存在包含方法。这是一个小例子;我可能会从大文件中提取数千个表、列、行组合。此外,这里假设必须以这种方式填充字符串变量。这是未处理的代码,会有麻烦。
考虑一个 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 那样是一种 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 之前那样重要,但仍然很好用;尤其是当您编写的代码会浪费时间而不是快速和肮脏的代码时。没有一个曾经在专家级别上使用过 VB 的人会声称 On Error Resume Next(内联错误处理)是一种语言中添加的最糟糕的功能。但是,它已被新手广泛滥用。
【讨论】:
以上是关于vbs 用On Error Resume Next跳过错误,但又想记录错误信息怎么办?的主要内容,如果未能解决你的问题,请参考以下文章
分配给On Error Resume Next的变量的值是多少?