I need to make a short premise: I am a software architect with more than 20 years of experience, not a junior asking directions. This is not to say "I know it all" (quite the contrary in fact) but just to give context and state that I have come across a legitimate doubt about something I thought was common knowledge and best practice and have done so for all this time.
I am working on different projects for different clients. I always check method's parameters for not being null and for other non valid states. A common precondition check you can find in my code is:
if (param == null) { throw new ArgumentNullException(nameof(param)); }
or
this.myField = myParam ?? throw new ArgumentNullException(nameof(myParam));
Also bear in mind that I use exceptions sparingly, I do not do user input validation with exceptions, I just use them to check and/or signal invalid states in the code, thus programming errors. It's extremely rare to find a try/catch block in my code at all.
One of my clients just asked me, without much margin to debate, to replace any similar occurrence with the use of custom exceptions. Meaning I am to define a CustomerNameArgumentNullException, CustomerNameFileNotFoundException, etc. and use those wherever I would use a standard exception.
Now I will comply, I have no right to debate the client request, but their lead programmer was pretty strong about this point on how this is the right way to go, that using default exceptions makes code less readable and also that custom exceptions make more easy to see what-is-what in Azure Application Insights. I tried to point out that he has the fully qualified name of the method that raised the exception so he can know which program, in which assembly and namespace and such but again, there was not much room to debate and it was not my place to do so.
So I've been wondering if he's actually right and I've been doing exceptions wrong all this time. If anyone has some more insight and/or some material I can read about that supports this theory.
Thanks.
While normally I'd suggest that a question like this should be closed as opinion-based, in this case there's really clear guidance from Microsoft:
Use the predefined .NET exception types
Introduce a new exception class only when a predefined one doesn't apply. For example:
Throw an InvalidOperationException exception if a property set or method call is not appropriate given the object's current state.
Throw an ArgumentException exception or one of the predefined classes that derive from ArgumentException if invalid parameters are passed.
In other words, your customer is asking you to go against guidance from the platform authors.
You may not be able to change the customer's mind to follow the guidance, but you can be confident that your approach is the recommended one, and their approach goes against that.
Following conventions like this is particularly important in Open Source projects - it's one thing to decide that you'll have your own conventions when only your team will work with the code, but if an application uses 10 different Open Source libraries, each of which has decided to create its own conventions, that's a nightmare.
There are two sides of the coin. Sure MS recommends this
Using custom exceptions gives you some advantages and disadvantages.
Advantages:
Abstraction
You can log telemetry data before you raise an exception. If not for custom exceptions, you'd have to catch an exception, log data and re-throw.
Customizing exception and error handling as needed by the app/services, etc
Disadvantages:
Telemetry data will have no stack trace if you are throwing custom exceptions.
Code maintenance and rigorous testing
There are various other things that come into picture, but catching an exception, logging metrics and then re-throwing (to preserve stack trace) the same exception is expensive.
Just my thoughts.
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
For the software we're developing at the company that I work for, we use a third-party library which is developed by a guy that we're constantly in contact with. His code is written in C++, and we use C# in the project.
Normally, his library functions return error codes. I decided to have different exception classes to cover different ranges of error codes. For example, one exception class for parameter handling errors, one exception class for main operation errors, one exception class for input value errors and so on.
He thinks it's not a good idea, and suggests using one exception class for the library that catches all the errors, and then fetches the error code from an XML file and outputs the problem to the user. He thinks, it's pointless to write more than one exception class. And also he says that he can't promise that the error codes will be the same in different versions of the library.
I think it's a good idea to have more than one exception class because:
There may be different situations that we need to handle the problem differently. Maybe when there's a parameter exception, do other stuff than just outputting an error. But he thinks his library is handling everything, and we should just stop the operation and output an error. I also can't think of many concrete examples of cases we need to handle differently, other than showing an error message. But I feel we may need it, and I'm afraid that I'm just violating the YAGNI principle.
I think if he turns out wrong, and we need to handle things differently in different cases, I'll have to introduce conditional code (if error was A then do this, if B then do that). And it will be difficult to handle.
I think it's a better idea to develop the program in a way that we can handle different types of exceptions differently. But then the guy has much more experience than me, plus he has much more credibility in the company (I'm a new intern) and I'm pretty new to software development and I feel like maybe he's right and I'm just trying to add extra code because it looks pretty, and violating the YAGNI principle.
Do you think we should go with one class or more? And if you think we should use more than one exception class, what are your reasons?
If the error codes can change from version to version, then no amount of work (or lack of it) is going to save you trouble of having to remap these somehow at some point. If you have exceptions for codes (or code ranges) then it's hardly going to be much more work than if you didn't have, when error codes do change (you're going to be rearranging what exceptions are thrown, just as you would have to be jiggling the messages around for one exception if you didn't have dedicated classes).
Besides, in general practice, by .NET convention, you should create a dedicated exception class for specific exceptions that aren't aptly covered by BCL-provided exceptions (excluding use of the some in there that are meant for abstraction only).
For some Microsoft input, consider this:
Applications and libraries should not use return codes to communicate errors.
And this:
Consider throwing existing exceptions residing in the System
namespaces instead of creating custom exception types.
But, following the Exception Design Guidelines,
[will] help ensure that you use the existing
exceptions, where appropriate, and create new exceptions where they
add value to your library.
Stick to your guns.
You're right. It's better to use several exception classes for different types of errors (for different error codes). Exceptions are somewhat successors of error codes, so it's better to use exception. And the approach that guy is offering is again using error codes, wrapped by one exception class.
SqlException with his Number comes on my mind. It's a hell to catch different types of errors by checking error code.
You should definitely use more than one exception class. Note though that there are a ton of built in classes already made in the System namespace such as ArgumentNull and friends.
If you want to see a case where multiple exceptions aren't used, take a look at COM interop. It's a dark place with generic exceptions thrown and their reasoning being justified by a single integer HRESULT. Trust me, you don't want to recreate that.
One really specific use case though is for instance whenever you just want to catch a certain exception. i.e.
try
{
lib.OpenFile(mypath);
}catch(FileNotFoundException e)
{
//handle gracefully and possibly "ignore" this error
}
Here, you want to do some other action if the file isn't found. However, if OpenFile throws an exception because mypath is null, you probably want this exception to bubble up and throw an error. (at least so you can log it or something). With a single exception class, this becomes more painful
catch(MyException e)
{
if(e.Reason=10)
{
}else{
throw; //rethrow exception(which makes debugging more difficult)
}
}
Consider a C# GUI application which uses a FileStream to read a file, chosen by the user through an "Open File" dialog.
In case the read fails with one of the exceptions, what is the correct way to report the failure to the user, in an user-friendly manner?
Should I invent my own message for each of those exceptions, or is there a way of obtaining a localized, user-friendly message that I could present verbatim to the user?
Edit
I'm asking whether .NET itself is able to provide me with a descriptive string that I can present (and which would be consistent with other .NET programs). I know that I can roll up my own, but I'd like to avoid that if there's a standard alternative.
You can have a set of localizable user exceptions with one of them being say FileUploadError. You can put a localized general information there. Throwing a few technical details might be a bit challenging, as it can be quite hard to get the right balance between technical details and a simple step that a user needs to take to fix an error.
My suggestion would be:
Have one user level FileUploadErrorException
Have a details property in it
Depending on the actual exception, suggest a user to try a few things
If you are catching an exception thrown by one of the .Net framework's File classes, then it is likely that the contents of the exception's .Message property will already be localized. The .Message property is supposed to contain localized, human readable text. How 'friendly' it is depends, I guess, but it might contain something you can embed within a more general and friendly paragraph.
Assuming you might write some method AlertUserWithMessage() to display the error to the user, this might be useful:
try
{
fileStream.Read(...); // or some other operation
}
catch(Exception e)
{
AlertUserWithMessage(e.Message);
}
If you want to include additional information that might be helpful to a support person diagnosing the problem, then you can also get the stack trace as a string from the exception.
try
{
fileStream.Read(...); // or some other operation
}
catch(Exception e)
{
AlertUserWithMessageAndStackTrace(e.Message, e.StackTrace);
}
Exception messages are by nature technical and describe what went wrong (at implementation level), as opposed to how to solve an end user's problem. On the other hand the intent of an error message presented to the user is to explain what failed and what action to take to remedy the problem. Exceptions messages and end-user error messages don't have the same purpose and aren't written for the same audience.
So for decent user experience, it is much better to map these exceptions to localized user-friendly advice on how to get around the problem. Sure, for technical users it could be nice to have some diagnostic feature that could give details of the exception (in which case having exception messages in English doesn't matter that much--English is really the world's technical language), or just point them to a log with all the details. But just throwing an exception message, even localized, at an end user is likely to baffle them.
For this reason I don't think localizing exception messages is much use. It's true that the .NET framework has localized exception messages for major languages, but I think that's more because there are developers who use these languages as their base language and do not necessarily have a good command of English. So the audience of these localized exception messages is still developers, not end users of a software product built in .NET.
Pretty new to C#, and I'd like to know how should I be using exceptions? I mean, not a mechanics level, but at a good practice level.
I'll use for example my calculator which tokenizes and the converts to RPN and solves problems given in RPN.
During the tokenizing step there's various invalid inputs, say "7.7.8" or "^&##", should I have separate exceptions for unknown symbols and invalid numbers? Is it wrong to say have a single exception and then a method in it containing the kind of error, to be given to the user?
I've really not been able to find much material on this kind of thing, so I thought I'd ask people with more experience than me.
-----Edit:
Thanks everyone for your awesome responses, I learned a ton today :) about my question, and even more for that matter.
Think about your lexer from the perspective of preconditions and postconditions. Here are two ways to design a lexer :
A lexer is a device which takes in a well-formed input string and outputs a lexical analysis. The input string is required to be well-formed; if it is not then the lexical analyzer fails with an exception.
A lexer is a device which takes an input string and produces a lexical analysis. Lexical analysis includes identification of and analysis of error conditions.
Do you know that the string you're going to pass in is correct, and you want an exception in the exceptional circumstance that it is incorrect? Or do you not know that the string is correct, and you wish the lexer to determine that?
In the former case, throw an exception. In the latter case, make the error analysis part of the output of the lexer.
Basically what I'm saying is do not produce vexing exceptions. Vexing exceptions are extremely irritating. If the caller of your code is calling it to determine whether the string is correct then they don't want that information in the form of an exception, they want it in the form of a data object that represents the error analysis. If the purpose of the code is to produce an error analysis then produce such an analysis as the normal operation of the method. Do not embed the analysis in an exception and make someone trap the exception in order to get it.
In my experience you should not use exceptions as part of the logic or control flow of the code. You should use it when there is a true exception. In your case, that would be, for instance, when there is an illegal character, character which shouldn't be there in the first place. If, however, the function is validating the string, you should not throw an exception when you find an illegal character, at least that is my opinion.
I use exceptions when database or file that "should" be there cannot be found, when a key/pair value is missing when it ought not to be etc.
Create exceptions for programmers, not users. Think what would be useful to a programmer calling your method? If there is specialized error handling code they should consider writing for a specific cause of an exception, then provide a specific type of exception so they can have a 'catch' block specifically for it. If the error handling code they should write is generic across various exception causes, then provide a more general type exception so they only have to code against that one.
This is a good reference on the best practices of exception handling in .Net.
http://www.codeproject.com/KB/architecture/exceptionbestpractices.aspx
A rule of thumb I like for determining if an exception is appropriate: If a function promises to do something and does not do it, it should throw an exception. A simple example would be Parse vs TryParse. Notice that the Parse functions promise to parse a string, then throw an exception if they cannot (e.g., because the string is in the wrong format). TryParse promises to try to parse, so it does not throw exceptions in if it cannot parse. In short, if your function makes a promise and fails to fulfill it, you should throw an exception.
Alternatively: do not throw an exception unless the preconditions of your function are unsatisfied. I interpret Eric Lippert's Vexing Exceptions as a discussion on what types of preconditions are inappropriate.
The general rule is KISS. You should only throw/create exceptions if you have need. There is no need to create a whole suite of exceptions if no one is every going to catch it.
In your case you could
Throw an InvalidArgument or create your own indicating that it is invalid user input.
Give a detailed error messages explaining what the problem was.
If you find that you are catching the exception and parsing the message and taking actions then its time to create custom exception/exceptions.
You could create a custom exception that has a "type" field, but any type of design that is dependent on exceptions is a bad one.
Exception should be for exceptional case, user input is not one of those case.
This question might help you When to throw an Exception
Use validation instead : Winform ui validation
all of your parsing exceptions should at least share a common base class so that the caller can catch any parsing exception without listing them all in the catch clause (and potentially forgetting one).
you can go down the road of making a taxonomy of subclasses but i wouldn't bother making such explicit distinctions until you have a need to do so. if the calling program takes the same action for all parsing errors then they can all be of the same class, varying only by display message. if it becomes clear that certain errors need to be handled differently, make a subclass. design around use cases.
as an aside: i think a given method should throw an exception if it cannot deliver what it promises, thus protecting the developer from assuming success in the case of failure. deciding which promises to make is a greater design question and you can look at existing parsing APIs for inspiration.
I'm working on a project and I'm just starting to do all the work necessary to globalize the application. One thing that comes up quite often is whether to globalize the exception messages, but ensuring that string.Format uses CultureInfo.CurrentCulture instead of CultureInfo.InvariantCulture. Additionally this would mean that exception messages would be stored in resource files that can be marked as culture-specific.
So the question is, should exception messages be globalized or should be be left in either the InvariantCulture or the author's country; in my case en-US.
Exception messages should rarely be displayed directly to the user. You need to think of the consumer for each string. Obviously pieces of text in the user interface need internationalizing, but if an exception message is only going to be seen by support (or is going to be visible to the user and then emailed to support when they click a button) then where's the benefit of translating it?
If you go too far, you could not only waste time and effort (and i18n can take a lot of effort) but you'll also make your support life harder as well. You really don't want to have to read log files written in a foreign language and translate them back to your native tongue.
It makes sense for Microsoft to internationalize their exception messages, because they will be read by developers from all over the world - but unless you're multinational with developers in multiple countries who don't share a common language, I wouldn't translate message which are really meant for dev/support.
typically, I don't.
Globalize strings that may be seen by a user, and you don't let your exception messages percolate up to the UI, right?
Right? :)
If you are going to be the one to deal with the exceptions, then either leave them in a language you can understand, or give them codes so you can look them up in your native language.
I assume by globalize, you mean i18n compliant which is usually called internationalize. Yes, internationalize all visible parts of the GUI, including diagnostic messages. The log file, which is where developers should go to get the real information such as the stack trace, should not be internationalized.
I'm about to start writing a .Net component which will be called from a VB COM+ service (the new component is a DLL which calls out to a webservice and returns based on the response). I'm not sure how to handle error conditions that might occur in the .Net code in the calling VB.
The two types of errors I'm worried about are:
exceptions that I might like to throw if a precondition is not met (e.g. the start date supplied as a parameter is less than 3 months after the end date supplied as a parameter; I might want to throw a StartDateNotValidException)
exceptions that are likely to happen as part of the webservice call (time out, 404 etc).
I'd like to return some specific feedback to the user and/or log some information to a log if either of these occur. I'd thought about returning Int return codes from the .Net code and avoiding Exceptions, but it's possible that the calling VB code may eventually be migrated to .Net, so I'd like to use Exceptions if possible.
I read on MSDN that COM Interop will automatically convert standard library exceptions to HRESULTs; has anyone had any experience using this? Could this be used to translate custom .Net exceptions to error conditions that I can handle in VB?
Thanks,
Nick
I am sure I have seen it done before, but it was in my previous job so I can't check the details. I think we inherited our exception classes from COMException and set the correct ErrorCode (which should be translated as HResult in unmanaged code). This is quite nice, because you can use HResult in unmanaged code as well as properly handle typed exception in managed client.
Please let me know if it actually works.
I ended up using the following method:
have a big Dictionary
that maps our application-specific
VB error codes to our
application-specific C# custom
exceptions
write a method that converts C# exceptions to VB error codes (and
vice-versa)
return an array of strings from the methods containing any business
exceptions that occurred in the
method call (there are only currently two of these)
The reason for doing this is that it was going to be too cumbersome to adapt our exception tree to extend COMException (more cumbersome than the above anyways). So, I never tried out inheriting from COMException and checking whether the ErrorCode got correctly converted to an HResult.
Thanks for the suggestion though, and apologies for not trying it out.