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 开发者_如何学Pythonwrong
would that be considered an exceptional case?
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.
.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.
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.
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.
}
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.
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.
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.
精彩评论