可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
If I put empty catch blocks for my C# code, is it going to be an equivalent for VB.NET's "On Error Resume Next" statement.
try
{
C# code;
}
catch(exception)
{
}
The reason I am asking this is because I have to convert a VB.NET code to C#, and the old code has ~200 "On Error Resume Next" statements although I am using a proper try {} catch {}
in my new code, but is there is a better alternative?
回答1:
I've found that VB programmers often littered code with many On Error Resume Next
statements out of (bad) habit. My suggestion would be to start with no suppressed exceptions, and see what actually breaks. There may not be as many issues as you think. Conversely, the more regression testing you can do, the better; there may be some edge cases that only work when errors are ignored.
Ultimately, you need to decide on an error handling strategy, whether it is graceful unwinding inside many try/catch blocks, or letting errors percolate to a top-level handler (both strategies have their uses).
If you end up having to suppress some exceptions to meet a deadline, at the very least log those exceptions so that the next developer working on your code doesn't get burnt by an empty try/catch
.
回答2:
Although sometimes this is acceptable, generally it indicates a code smell. If you're 100% sure you want to swallow the exception that has occurred you can do it the way you have, but generally if an exception is thrown you should do something.
Generally you can achieve the same outcome with well designed code. If you're currently experiencing a specific error, add it to your question, but if you're asking just out of curiosity, no there isn't an equivalent, and that is a good thing.
回答3:
No, it's not the same.
When using On Error Resume Next, VB would skip to the next line if an error occurs. With try/catch, execution jumps to the catch block if an error (exception) occurs.
回答4:
You need to analyze the On Error Resume Next
statements one by one and see what their purpose is. Some may be just sloppy code, but there are valid reasons for On Error Resume Next
in Visual Basic 6.0 code.
Some examples of why to use On Error Resume Next
in Visual Basic 6.0 code:
To check if a given key exists in a Visual Basic 6.0 collection. The only way to do this is to access the element by key, and handle the error that is raised if the key does not exist. When converting to .NET, you can replace this by a check for the existence of the key.
Parsing a string to an integer. In .NET you can use TryParse.
回答5:
Although On Error Resume Next
is certainly abused more than it's used legitimately, there are places where it would be helpful even in VB.NET.
Consider a program which assigns values to a large number of Excel properties, such as defaults to all printer parameters -- there are a zillion printer parameters in Excel. Later versions of Excel might have properties which earlier versions don't support, and it isn't trivial to figure out which ones are supported in each version. The program should assign a value if the property exists but ignore the property if an older version of Excel is used.
The "right" way to do this with VB.NET would be to determine which printer properties are supported by each version of Excel, read the version in use, and only assign to properties that are implemented in that version. That would require a lot of research and some code, all for little benefit. On Error Resume Next
would be a more practical solution.
And, unfortunately, I'm faced with precisely this problem now. The workaround I'm going to try is to write a subroutine which just assigns one value to another, ignoring errors. I'll call this subrouting in place of each assignment statement. Not too terible, but not so great either.
回答6:
"On Error Resume Next" allows for "Inline Error Handling", which is the expert level error handling in VB. The concept is to handle errors line by line, either performing an action based on the error or ignoring the error when beneficial - but running code in the sequence in which it is written and not using code jumps.
Unfortunately, many novices used "On Error Resume Next" to hide either their lack of ability or out of laziness from those using their applications by ignoring all errors. Try/catch
is block level error handling, which in the pre-.NET world was intermediate by design and implementation.
The problem with "On Error Resume Next" in VB.NET is that it loads the err object on every line of executing code and is, therefore, slower than try/catch
. I'm somewhat alarmed that this forum checked and promoted an inane answer that claimed using On Error Resume Next is a bad habit and code litter. This is a C# forum; should it really be used for C# programmers to take shots at another language that they aren't well versed in?
https://msdn.microsoft.com/en-us/library/aa242093(v=vs.60).aspx
It being said that intermediate C# programmers with no real VB experience shouldn't try to keep C# dumbed down and feature limited because of their weird disdain for another "Microsoft Net" language, Consider the following code:
//-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();
If the xml usually has a value for Field3 but sometimes not; I'm going to get an annoying error that the table doesn't contain the field. I could care a less if it doesn't because it's not required data. In this case, ON Error Resume Next would allow me to just ignore the error and I wouldn't have to code around each line of code setting the variables checking for the existence of the table, row and column combination with Contains methods. This is a small example; I might pull in thousands of table, column, row combinations from large files. Also, assume here that the string variables must be populated this way. This is unhandled code and there will be trouble.
Consider a VB.NET and ON Error Resume Next Implementation:
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()
In the above code, it was only necessary to handle one possible error condition; even though there were two errors before the third one was handled. RAD development needs On Error Resume Next. C# is my choice of languages but it isn't as much a RAD language as VB for many reasons. I hope all programmers realize that several major languages (i.e. C) just run and don't halt execution on unhandled errors; it's the developers job to check for them where they think necessary. On Error Resume Next is the closest thing to that paradigm in the Microsoft world.
Luckily, .NET does give many advanced choices to handle these situations; I eluded to the Contains. So, in C#, you have to beef up your knowledge level of the language and you properly, according to the C# language specification, work around such issues. Consider a solution for handling a large block of repetitive lines of code that could contain an annoying throw away error:
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);
}
Although in a try/catch block, the lambda function is checking for the existence of every table, row, column combination that is being pulled from the dataset that was populated dynamically by the xml. This could be checked line by line but would require a lot of excess code (here we have the same amount of executing code but far less written code to maintain). This unfortunately might be considered another bad practice of "One Line Functions." I break that rule in the case of lambdas and anonymous functions.
Since .NET offers so many ways to check the status of objects; On Error Resume Next isn't as vital to VB experts as it was prior to .NET but still nice to have around; especially when you're coding something that would be a waste of time to not code fast and dirty. To you Java converts to C#; join the Microsoft world and stop pretending that if 10000 intermediate Java and C# programmers say it, than it must be true because if one top level Microsoft Guru (such as any one of those who created the VB language and .NET) obviously contradicts you in their development of .NET itself, it is false and you look foolish. I want all the functionality I can get in C# and VB and F# and any other language I need to use. C# is elegant but VB is more evolved due it's much longer tenure but they both do the "Same Thing" and use the same objects. Learn them both well or please resist commenting on either in comparison conversations; it's nauseating for those of us who have been around since the mid nineties using Microsoft technologies at a high level.
回答7:
Using "On Error Resume Next" is not a good idea for error handling (of course, this is my personal opinion, but seems that most of the developers agree with me though). As other guys advised you in previous posts, use Try...Catch...Finally
(whether in VB.NET or C#).
This is a very smart option for error handling, but it will also allow you to do nothing with the error (an empty catch block) :) I would suggest you to put every line of code (which may cause error) in separate Try...Catch Block
, so that you would have the opportunity to do whatever you want if an error occurs.
Happy Coding guys :)
回答8:
The proper .NET replacement for "on error resume next" is the use of Try___ methods. In Visual Basic 6.0, to find out if a key existed in a Collection, one had to either search the collection manually (horribly slow), or else try to index it and trap any error that occurred if it wasn't there. In VB.NET, the Dictionary object (which is an improved version of the old Collection) supports a TryGetValue
method, which will indicate whether or not the attempt to get the value succeeded, without causing an error if it did not. A number of other .NET objects support similar functionality. There are a few methods which should have "try" equivalents but do not (for example, Control.BeginInvoke
), but there are sufficiently few of them that wrapping them individually in a Try/Catch
is not too onerous.
回答9:
I happen to think those people who invented "On Error Resume Next" did have something in mind when they created it.
The answer to your question would be no, there's nothing equivalent to this construct in C#.
We have in C# and .Net a lot of functions that are so hungry for care and attention it gets tiring after a while to cater to everybody's "exceptional behavior". When almost everything can throw an exception the word itself looses it's meaning somewhat.
You're inside an iteration and what should you do if few thousands of the million items happen to be exceptional ? Resume Next could be one of the handy answers.
回答10:
As been said by @Tim Medora, you have to make an effort to avoid using such approach when coding. However, in some cases it is useful, and it is possible to emulate such behavior. Here is a function and an example of using it.
(Note that some code elements were written using 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 Collections.GenericArrayList<Exception>() : 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();
}
Example, instead of:
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 { }
you can:
var a = 19;
var b = 0;
var d = 0;
OnErrorResumeNext(
() =>{a = a / b;},
() =>{d = a + 5 / b;},
() =>{d = (a + 5) / (b + 1);}
);
回答11:
I am an old hat at VB6. First a short lesson...
There are reasons to use On Error Resume Next. Mostly for readability. In VB6 you have two ways to implement Error trapping. You can use an "inline" On Error Resume Next like this.
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
Or, you may see this:
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
But in old VB6 code you will likely also see this...
Sub PerformThis
On Error Resume Next
End Sub
Regardless it is pretty straight forward to convert these cases into Try Catch... If you need to sink an error use a quick "inline" looking On Error Resume Next just do this..
try { _objectinfo.Add(_object.attribute1); } catch (Exception _e) { }
You can also raise the try catch to the calling routine, by encapsulating the code into a subroutine... So if you need to sink the entire subroutine do this...
try { PerformAction(); } catch (Exception _e) { }
Do this in the case where PerformAction() subroutine contains an On Error Resume Next at the top of the code, use the Try Catch in the calling subroutine
Good luck...