9

I have created a class that parses some document from file.

class Parser
{
  public Parse(string fileName)
  {
    ///
  }
}

Sometimes there can be parsing errors in that case parser has to return certain data. I have created special class for that.

class ParsingError
{
 // some data
}

How can I correctly deal with such errors. I have at least two options:

create my own exception or return value.

Option One

myParser.Parse(fileName, out error);

Option Two

try
{
  myParser.Parse(fileName)
}

catch(MyParsingException ex)
{
  // use ex.Error field
}

UPDATE

If I am not mistaken the ideology behind the exception is that it should deal with something exceptional, that is some situation that the method is not intended to deal with.

This leads me to wonder if for example:

the parser finds unknown field in the file, or the encoding is wrong

would that be considered an exceptional case?

shawty
  • 5,729
  • 2
  • 37
  • 71
Captain Comic
  • 15,744
  • 43
  • 110
  • 148
  • matter of taste? The parserfunctions that i know in c# use the exception. – jwillmer Mar 28 '11 at 14:03
  • possible duplicate of [.NET Return value vs thrown Exception Design question](http://stackoverflow.com/q/4884539/102112) – Oleks Mar 28 '11 at 14:04
  • Is there anything more to this question other than which is better? That question is answered in several questions e.g. http://stackoverflow.com/questions/99683/which-and-why-do-you-prefer-exceptions-or-return-codes – StuperUser Mar 28 '11 at 14:05
  • Ok my question was already asked. I see. Vote to close it, I don't mind. – Captain Comic Mar 28 '11 at 14:07
  • 1
    But thanks for the links guys I am already reading. – Captain Comic Mar 28 '11 at 14:09
  • I am leaning towards both options. It seems as if it is a matter of how you **define** an exceptional case. The subject overall is dependent on your _personal judgement_. I have two questions about this topic on SO and haven't received a fulfilling answer yet. – anar khalilov Dec 04 '13 at 13:01
  • “ the use of exceptions for control flow is an anti-pattern” https://softwareengineering.stackexchange.com/questions/189222/are-exceptions-as-control-flow-considered-a-serious-antipattern-if-so-why – Michael Freidgeim Nov 07 '21 at 11:07

7 Answers7

16

Think of how typical it is to have a parsing error. If it's typical - favor a return value. Exceptions should be used for things that are not normal.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • Nice answer. I still have a question, though. Isn't deciding how typical it is dependent on your personal judgement? It kind of feels so. For example, when you try to convert the "asd" string to an integer, an exception will be thrown. Can we say that it is not typical even though this error is a pretty common one? – anar khalilov Dec 04 '13 at 13:05
  • @Anar: In such cases you typically have two distinct functions (or one with a flag) - one will be "try parse and return an error code" and the other will be "parse this and throw an exception if anything" and the second one will typically call the first one internally and the developer will then decide which one to use. He will use the first one for dealing with user input and the like and the second one for parsing something which comes from a reliable source. – sharptooth Dec 04 '13 at 14:00
  • In this context, what I have difficulty to understand is that how can one define "_a reliable source_" so that Parse (not TryParse) can be used? What I am trying to say that this reliable/non-reliable thing is a matter of interpretation and our interpretation might naturally be wrong. Why is using exceptions or return values dependent on our might-be-false interpretations? – anar khalilov Dec 04 '13 at 14:10
  • @Anar: You have to choose between "try parse" followed by a check (which you can easily forget) and "just parse" not followed by a check (and so nothing to forget). If your analysis happens to be wrong your application will not work as you expected, that's it. – sharptooth Dec 04 '13 at 14:14
  • See also https://softwareengineering.stackexchange.com/questions/189222/are-exceptions-as-control-flow-considered-a-serious-antipattern-if-so-why – Michael Freidgeim Nov 07 '21 at 11:05
5

.NET land's philosophy on exceptions is a bit different than other platforms. It doesn't take long in .NET land to realize you're no longer in OZ, and that exceptions are thrown often.

From MSDN on .NET 4: Do not return error codes. Exceptions are the primary means of reporting errors in frameworks.

From MSDN on .NET 4.5: An exception is any error condition or unexpected behavior that is encountered by an executing program.

An example they give is if a client can't connect to an endpoint. So if you consider that sometimes websites are unavailable for networking or other reasons, which doesn't quite fit the traditional definition of "exceptional", you can get a feel for how they creators intend exceptions to be used.

Greg
  • 643
  • 9
  • 15
  • 1
    The second part of the statement from MSDN on .NET 4.5 must be added: "Exceptions can be raised because of a fault in your code or in code that you call (such as a shared library), ...", meaning that **Exceptions are for code faults, not for data faults**. – Lightman Oct 27 '15 at 18:39
3

I would go with option three

ParseResult result = myParser.Parse(filename)

Here ParseResult can provide more detail about the outcome of the parsing, both positive and negative.

If the failure condition is very rare and would be considered an unexpected result then I would go for your option two and throw an exception. Of course the final solution might be a combination, where common errors are returned in the ParseResult but exceptional conditions like failure to open the file etc. are surfaced as exceptions.

Chris Taylor
  • 52,623
  • 10
  • 78
  • 89
2

Error flags or return values are generally better in cases where the immediate caller is going to deal with the invalid condition. Exceptions are generally better in cases where there are going to be many function calls which could fail in a particular way, and fault handling for all those function calls should be identical.

Oftentimes the author of a method can't t know which scenario will apply to its callers (indeed, it's common for some callers to better fit one pattern and some the other). Microsoft's preferred way of handling this is to use the pattern:

Thing GetThing(int param1, string param2);
bool TryGetThing(int param1, string param2, out Thing result);

That's certainly a better concept than confining callers to fit one pattern or the other, though I don't like the particular implementation. Microsoft explicitly recommends using separate methods, rather than using one method with a parameter that indicates whether a failure should throw an exception, but that philosophy comes at a cost: it means that if one of the steps of GetThing or TryGetThing can be done with a "do" or "try" method, the code for GetThing and TryGetThing will have to be largely duplicated, with one calling "do" methods and the other calling "try" methods.

An alternative approach would be to have a delegate or interface-type object which indicates what a "try" method should do if an exception occurs. For example, one could have a function:

Thing TryGetThing(int param1, string param2, bool ThrowOnError, out ErrorInfo errInf);

possibly with an overload which, if the last two parameters are omitted, will calls the above with true for ThrowOnError, and a dummy variable for errInf. If the methods used by TryGetThing follow a similar pattern, it may be able to call them without having to duplicate code for the try/do cases.

supercat
  • 77,689
  • 9
  • 166
  • 211
2

That depends if the MyParsingException is just a derived class from System.Exeption, or it contains additional information about what went wrong while trying to parse the file. If there is no such info, then I think that the Parse method should return maybe a string, or null if an error occurred:

 public string Parse(string fileName)
 {
     string res = null;
     try
     {
        /// parse the file, assign parse result to res
     }  
     catch
     {
        res = null;
     }
     return res;
 }

or, if the exeption is really helpfull, contains information about the file (name) , line number... etc:

public string Parse(string fileName)
 {
     string res = null;
     int errorLine = -1;  
     try
     {
        // foreach line of text to parse -- errorLine  = lineNumber;
        /// parse the file, assign parse result to res
     }  
     catch (Exeption ex)
     {
       MyParsingException myEx= new MyParsingException ("parsing error", ex);
       myEx.Data["fileName"] = fileName;
       myEx.data["lineNumber"] = errorLine ;
       throw myEx;
     }
     return res;
 }
 // then you can have some really useful info:

try
{
    myParser.Parse(fileName)
}
catch(MyParsingException ex)
{
  // use ex.Data to get the "fileName" and "lineNumber" properties.
}
Alex Pacurar
  • 5,801
  • 4
  • 26
  • 33
1

If your API says it handles parsing errors then this isn't an exceptional situation and perhaps parsing errors should be returned. For other stuff, like missing files, locked files, invalid input (other than dodgy parsing) you should throw exceptions.

Adam Houldsworth
  • 63,413
  • 11
  • 150
  • 187
0

For me, it depends on how I plan to consume the error and what kind of error it is. The context of the method also plays a part. If the method is expected to hit an error in the xml every once in a while, well, then it's not an exception in my eyes, and should be treated accordingly.

Let's say I'm writing an XML validator, then returning an error is the way to go. If I'm writing an XML configuration parser, an exception would seem more appropriate.

Kristoffer Lindvall
  • 2,674
  • 1
  • 18
  • 27