try
{
C# code;
}
catch(exception)
{
}
我提出这个问题的原因是因为我需要将VB.NET代码转换为C#,而旧代码中有大约200个"On Error Resume Next"语句,尽管我在新代码中使用了适当的try {} catch {}
,但是否有更好的替代方案呢?
try
{
C# code;
}
catch(exception)
{
}
我提出这个问题的原因是因为我需要将VB.NET代码转换为C#,而旧代码中有大约200个"On Error Resume Next"语句,尽管我在新代码中使用了适当的try {} catch {}
,但是否有更好的替代方案呢?
On Error Resume Next
语句。我的建议是从没有抑制异常开始,看看到底会有哪些问题出现。你可能认为出现的问题没有那么多。相反,你进行的回归测试越多,就越好;可能有一些边缘情况只有在忽略错误时才能正常工作。try/catch
语句弄伤。虽然有时这是可以接受的,但通常它表明存在代码异味。如果您百分之百确定要吞掉已发生的异常,可以按照您的方式执行,但通常如果抛出异常,则应该采取某些行动。
通常情况下,您可以通过精心设计的代码实现相同的结果。如果您目前遇到了特定的错误,请将其添加到问题中,但如果您只是出于好奇而问,那么没有等价物,这是一件好事。
On Error Resume Next
被滥用的情况比正常使用的情况更多,但在VB.NET中有些地方使用它仍然很有帮助。考虑一个程序,它为大量的Excel属性分配值,例如默认打印机参数--Excel中有无数的打印机参数。较新版本的Excel可能具有较早版本不支持的属性,而确定每个版本支持哪些属性并不容易。如果属性存在,则程序应该赋值,但如果使用较早版本的Excel,则忽略该属性。在VB.NET中做到这一点的“正确”方法是确定每个Excel版本支持哪些打印机属性,读取正在使用的版本,仅分配在该版本中实现的属性。这需要大量的研究和一些代码,但好处很少。On Error Resume Next
将是一个更实际的解决方案。不幸的是,我现在正面临这个问题。我要尝试的解决方法是编写一个子例程,只是将一个值分配给另一个值,忽略错误。我将调用这个子例程来代替每个赋值语句。这不太糟糕,但也不是那么好。try/catch
是块级错误处理,在前-.NET时代是通过设计和实现中级别的。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();
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()
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);
}
On Error Resume Next
语句并看看它们的目的是什么。有些可能只是懒散的代码,但在Visual Basic 6.0代码中使用On Error Resume Next
也有合法的理由。On Error Resume Next
的一些示例:
检查Visual Basic 6.0集合中是否存在给定键。唯一的方法是通过键访问元素,并处理在不存在键时引发的错误。转换为.NET时,您可以通过检查键的存在来替换此方法。
将字符串解析为整数。在.NET中,您可以使用TryParse。
On Error Resume Next
是同样糟糕的。On Error Resume Next
存在的原因是有其它语句 - IFs
来捕获单个错误类型,而 On Error GoTo 0
则用于恢复错误引发而不是跳过所有错误。 - MikeFileName
值不足以作为指示器…… - Cody Gray不,它们不一样。
使用 On Error Resume Next 时,如果出现错误,VB 会跳到下一行。而使用 try/catch,在发生错误(异常)时,执行会跳转到 catch 块。
Try...Catch...Finally
(无论是在VB.NET还是C#中)。Try...Catch Block
中,这样如果出现错误时,您就有机会做任何您想做的事情。
程序员们,愉快的编码 :)正如@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);}
);
“On error resume next”在.NET中的正确替代方法是使用Try___方法。在Visual Basic 6.0中,要查找集合中是否存在某个键,必须手动搜索(非常缓慢),或者尝试索引它并捕获任何错误,如果不存在则会出现错误。在VB.NET中,字典对象(这是旧集合的改进版本)支持TryGetValue
方法,它将指示获取值的尝试是否成功,如果没有成功,则不会导致错误。许多其他.NET对象支持类似的功能。有一些方法应该具有“try”等效方法,但实际上没有(例如Control.BeginInvoke
),但它们很少,逐个包装它们在Try/Catch
中也不太繁琐。
On Error Resume Next
,没有其他替代方案,并非是无意的疏忽......为什么可能需要它?如果您解释了想法背后的动机,我确信这里有人可以给您提供更好的解决方案。" - Cody Gray