I use Custom Exceptions to communicate the nature of the error.
For example, I like using the framework provided "ArgumentNullException" to check arguments. Then later, when I see this error either in the debugger, or in an error log, I immediately know the nature of the error without reading any further.
The other end of the spectrum is the InvalidOperationException which could mean pretty much anything.
The alternative to custom exceptions is detailed error messages. That's ok, but by making a custom exception such as ConnectionFailed is more meaningful. Then the message itself can give greater details.
When creating such custom exceptions, I do not add any new properties. The reason for this is that if you have an error logger, you want it to work on all exceptions. If you add a special property, then the error logger is going to ignore it. For example, if you use MSTest, when you run your test and it fails, the custom properties are not displayed. But if you stick with the Message property of the baseclass, it will display just fine.
So the subclassing is very simple:
public class NavigationException : Exception{
public NavigationException() {}
public NavigationException(string msg) : base(msg) {}
public NavigationException(string msg, Exception inner) : base(msg, inner) {}
}
This is very straightforward, works with any error logger, and when I see it, I know it was a Navigation problem and I can view the details if needed.
Greg