A: 

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

mquander
I think you have this backwards - the one that takes an inner exception is so that if your code catches another exception, you can wrap your exception around it
1800 INFORMATION
OK, good point.
mquander
+6  A: 

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.

Matthew Flaschen
It won't just make it less intuitive - it will specifically disable it from working, either in exception remoting scenarios or when the caller needs to use it as a wrapper for another exception.
Daniel Earwicker
True. The OP /may/ have a good reason not to care about those, but probably not.
Matthew Flaschen
A: 

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.

Daniel Earwicker
I was not aware that the parameterless constructor was required for the exception routing; I thought the serialization constructor handled that. This is one area of exceptions that I have zero experience or knowledge in.
Alexis
It depends what serializer you use - XmlSerializer requires a parameterless constructor, the other methods don't.
Daniel Earwicker
+6  A: 

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.

Fredrik Mörk
+2  A: 

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

jrista
You should implement the serialization ctor EVEN if you don't plan on being in a distributed scenario. Since it's used in remoting to pass the exceptions between domains, it may be called inside your process if you happen to have several AppDomains (intra appdomains communication is likely to become the last use case of remoting, since it's being slowly replaced by WCF for Out Of Process calls). You never know how your code will be called. If someone wishes to have your code called inside a plugin in an app, it will end up in another appDomain and you'll need this constructor.
Yann Schwartz
Very good point. Its generally just a best practice to implement the standard constructors and serializability because .NET will use and possibly "rethrow" or recreate and wrap your exceptions in a wide variety of places.
jrista