I miss Visual Basic's "On Error Resume Next" in C#. How should I be handing errors now?
Asked Answered
O

6

13

In Visual Basic I wrote just On Error Resume Next in the head of my program and errors were suppressed in the entire project.

Here in C# I miss this feature very much. The usual try-catch handling for every single procedure is not only very time-intensive, it brings undesired effects. If an error is encountered, even if handled, the code doesn't continue from the point it occurred. With On Error Resume Next, the code continued from the point of error, skipping just the function call that caused the error.

I am not deeply involved with C# yet, but maybe there exists in C# a better error handling than the primitive try-catch.

I also would like to have the module or function name where the error occured as well as the the line number in my error message. The Exception class doesn't provide that features as far I know. Any ideas (managed, of course, without involving any process classes on my own application)?

How do you handle the errors in bigger projects? I hope I do not have to add a try-catch to each method. Somehow C# throws many errors - that seems to be typical of the language.

My Solution which I found to re-solve several of my problems:

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
    }

   }
Overlong answered 21/7, 2012 at 21:39 Comment(11)
Exceptions have a meaning. Just ignoring them is chaos.Verbal
That's probably a bad sign that you need a global try/catch. Most of your code should NOT produce an error, and only really in rare cases should you be having exceptions thrown.Nondisjunction
@feedwall: No, you should find those errors and fix them. What you're experiencing is not typical. You might want to start writing unit tests...Collagen
This is actually a good question. It suggests the OP is currently doing all kinds of things wrong, but it explains the situation pretty clearly, and the answers should be able to give enlightenment to anyone in the same situation. A good question indicating a poor programmer is more useful than a bad question from a good programmer, IMO :)Collagen
Out of curiosity, did your VB program(s) work well?Clabo
If the "crap" was just skipped, as you say, then why were you calling it? feedwall, I'm telling you straight up - having worked on projects like the one you describe, your app did not work well. Data got corrupted. You were lucky not to have any devastating failures as a result (that you know of). Trust us here - you'll produce much higher quality work without that directive.Ethanol
Forget F1. Review the exception's properties (as I describe in a comment below). Read what it's telling you. .NET's error reporting is usually verbose and exceedingly helpful. Plug the exception's Message property (removing any information specific to your app) and classname into Google, if you need more information.Ethanol
See my answer. You have to look in the inner exceptions if the exception itself ins't self explanatory.Rossierossing
Also, this questions deserves upvotes. This seems a common sense for new VB programmers (if it's possible by now with all kinds of new and "refactored" languages in scene) and old self learners that don't get a stop for reading good references.Rossierossing
@rcdmk: It's been upvoted five times... and downvoted five times. I think a lot of folks are reacting to the "primitive" comment, and other aspersions thrown at the language. You're right, though - this is a good question, as shown by the great answers.Ethanol
This is indeed an interesting question, precisely because it shows an, let's say, interesting approach to error handling. Still, +1 for asking the question.Popelka
C
32

Continuing after errors as if nothing's happened is a terrible way of programming.

Can't work out the new balance of the account? That's okay, let's just store it as 0. No-one will ever know, right?

try/catch blocks should actually be relatively rare, because there are relatively few errors you can really recover from. Typically you should have one try/catch block at the top of some logical operation, so that if it fails you can inform the user and continue with other entirely separate operations - or terminate the app completely, depending on the kind of application you're writing. (Web apps are a good example here: you can fail the request, hopefully taking care that you don't have nasty persistent side-effects, and continue to handle other requests.)

Where there are places you legitimately expect errors you can recover from, catch those specific exceptions and handle them appropriately (e.g. falling back to writing to a file if writing to a database fails). Again, these are relatively few and far between. If you find yourself writing a try/catch block in every method (or even every class) then you're probably handling exceptions inappropriately.

I also would like to have the module or function name where the error occured as well the line number in my error message. The Exception class doesn't provide that features as far I experienced.

Yes it does. The stack trace shows the type, method and line number (where available) for each frame in the stack... as well as a (hopefully useful) message, of course. Oh, and potentially a nested exception too, if one failure was caused by another.

Somehow C# throws many errors on execution always, that's language typical.

Nope, that just suggests you're Doing It Wrong.

Collagen answered 21/7, 2012 at 21:42 Comment(11)
Look to the StackTrace and Message properties of the thrown exception, @Overlong (which Visual Studio displays, if running from the debugger). Prowl around - there's often useful information in other properties of subclassed exceptions, and InnerException will sometimes contain a nested exception.Ethanol
@feedwall: If you don't know what causes an exception, you should look at it very carefully indeed. Copy the stack trace somewhere (if it's not already in a log) and ideally write a unit test to reproduce the problem. Then fix it. Don't just ignore it.Collagen
What do you hope to get from Err.Number(), the line number of your source that triggered the exception? Review the StackTrace property for that.Ethanol
@feedwall: You shouldn't be thinking about exception numbers. Use the exception type, combined with the message - and the stack trace, of course.Collagen
@feedwall: "Maybe I could autoclose the thrown error somehow with SendKeys and press the "Continue" button for the user, but I am not sure how exactly I would do that." No no no! Please read all the answers here - you should absolutely not want to suppress errors and just keep going like this. Your users will not appreciate your app overwriting good data with bad because you have bad code you decided to ignore.Collagen
Without intending to be rude, @feedwall, I'll just say: what you're proposing is very, very wrong. Don't do it. You're frustrated, and you're lashing out a bit. Take the weekend and step away.Ethanol
@MichaelPetrotta: I haven't seen the OP lashing out - have some comments been removed? What I've seen so far is wrong-headed, but polite :)Collagen
Oh, he's not lashing out at us, Jon - sorry to imply that. But when I read a proposed solution like "Maybe I could autoclose the thrown error somehow with SendKeys and press the "Continue", I picture a person on his very last thread of patience, growing an ulcer and about to throw his laptop out the window. I've been there, and it's not healthy. Much better to step away.Ethanol
@MichaelPetrotta: Oh agreed on the frustration side. I have a lot of sympathy for someone being told that their approach for the last N years is simply bad. Glad to hear my opinion of the OP's politeness here is okay though :)Collagen
@feedwall: I rarely find ex.Message cryptic when used with the rest of the stack trace. You haven't given any examples of the problems, and the stack trace should show you exactly where the exception occurs. Don't write any more features until you've gone through and fixed all the problems you've been seeing. It sounds like you're not quite ready for working out exactly where to handle exceptions yet - you need to understand the exceptions first.Collagen
@feedwall: " What would I have to do exactly to improve my error handling?" If you would like specific help with error handling, feel free to ask a new question with a small sample program that shows a problematic error. Then you'll probably get help about how to handle errors.Popelka
T
18

No.

Speaking as an ex-VB programmer, please let me assure you: that is the worst and most abused feature ever added to any language ever. Here's the idea instead:

  1. write code that doesn't error ... unless something happens that is actually a problem. This may involve checking your assumptions before you do things; great: do that
  2. only catch problems you were expecting; swallowing all errors is just asking for massive problems

As already noted by Jon, it is actually pretty rare to need exception handling all over the place. Usually you just let an exception bubble up to a higher caller, because something bad just happened. And when I do have a try, it is more commonly try/finally (not try/catch) - with using and lock (etc) being special-cases of those for convenience.

Tallbott answered 21/7, 2012 at 21:43 Comment(0)
R
5

No, you can't. This is not possible in C# (and should not be in any other language).

The true use for this in VB was to make error handling in some part of the code, just like try / catch. You enable it, check with Err.Number <> 0, do your work and restore the error flow with On Error GoTo 0 or redirect to a label that follows a different path to treat the error or continue the execution On Error GoTo someErrorCase:.

You must have learned to program alone or with a person that doesn't do it the right way. Ignoring errors is a bad habit, and more than this, its an horrible thing to just follow with code. After all, errors are possible.

Trust me. I was a VB programmer and it was enlightening when I've stopped to read on best practices.

Just to add some more, try to use Option Explicit too, it may sound more work on declaring all variables, but it will give you more confidence of the code, because the type check will constrain some common errors.

Also, C# exceptions are kind of very usefull and have all info you may want. If you haven't got the problem with the exception itself, just open it and look in its inner exception (I catch me always looking the inner exceptions when developing for web, since all code is at higher level).

Rossierossing answered 21/7, 2012 at 21:55 Comment(2)
@Michael Petrotta Thanks for correcting my typos and spelling.Rossierossing
+1 for actually explaining how the feature evolved. I would never have thought there actually is a sane way to use it.Popelka
M
4

Actually, exceptions are rather the exception, they don't happen all the time. When they do happen, you want to know they happened, and either handle them or shut down your process. Most of the times letting an exception go unhandled is going to lead to very unexpected results.

Mycology answered 21/7, 2012 at 21:42 Comment(0)
S
2

You have been using that VB feature wrong, and you are so lucky that you can't use it like that in C#.

When using the feature in VB you are supposed to check the error status after every operation that could result in an error. When used correctly, it's not less code than having try...catch blocks around every operation that could result in an error.

So, if you think that you have to do more error handling in C#, you have been doing far too little error handling before.

Synge answered 21/7, 2012 at 22:6 Comment(0)
C
0

"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.

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

        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()

In the above code, it was only necessary to handle one possible error condition; even though there was an error loading the file. On Error Resume Next actually allowed me to resume as intended, which allowed me to check the string condition and use my alternate string (I'm well aware that I could have checked to the existence of the file also and avoided the file error but if it were a good file with nothing in it, strXML would be an empty string). The error that was critical to the rest of the code was handled and the method was exited because the loaded dataset was paramount for the rest of the processing beyond it (processing that could be run through ignoring any errors if desired). The file error could be ignored as I ignored it or I could have checked the error condition and logged it.

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. No one who has ever used VB on an expert level would ever claim that On Error Resume Next (inline error handling) is the worst feature ever added to a language. However, it has been widely misused by novices.

Clothier answered 12/12, 2015 at 19:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.