Well, the constructor that takes an inner exception is pretty much necessary to make a custom exception properly usable. Without it, if someone caught your exception, they couldn't fire off a more descriptive or appropriate exception while preserving your original one (and the information it carries, like the stack trace.)
This is a warning, not a requirement. It's basically principle of least surprise. Providing all 4 makes it easier for people used to "regular" C# exceptions to use yours. If you have a good reason to ignore the guideline, do so. But it will make your class a little less intuitive.
The parameterless and Serialization constructors are used by generic "exception routing" code that needs to move exceptions around between domains (e.g. across the internet between a service and a client).
The one that takes another Exception
is so that it is possible to chain all exceptions via the InnerException
property.
Finally, there's the one that takes a message string, which helps to make use of exceptions reasonably consistent.
You have gotten some good answers. I just want to add that providing these extra constructors does not necessarily require a lot of coding. Since they are already implemented in the base class, you can simply let that one do the work:
public class MyCustomException : Exception
{
public MyCustomException() : base() { }
public MyCustomException(string message) : base(message) { }
public MyCustomException(string message, Exception innerException) : base(message, innerException) { }
// and so on...
}
So you will only need to implement code where the behaviour of your exception deviates from that of the base class.
Implementing the standard exception constructors allow people to use your exception in a standard, familiar way that is built into all existing .NET exceptions. The first three can be optional, if for some reason you don't want one of them to be used (although why you would want that I couldn't fathom.) However, the last one is the deserialization constructor, and if you wish your exception to be supported in any kind of distributed environment (.NET Remoting, ASP.NET Web Services, WCF, etc.), then its is pretty much essential.
Without a deserialization constructor and the [Serializable] attribute, your exceptions won't function in a distributed environment, and could possibly cause other problems. Given that, and the aspect of familiarity to well-versed C# developers, its best to implement at least the 4 standard exception constructors, and mark your exceptions with [Serializable].