Patrick Cauldwell has a good list of Programming Guiding Principles he calls This I Believe: The Developer Edition. I've blogged about them before.
I got an email today that went something like this:
I have an interface called IStorageConnection and one of its methods is Save(...). The storage connection object available to user is configured through configuration files. The storage could be either the FileSystem or the Database. In that case, how is the consumer of the IstorageConnection interface going to know that exceptions to expect? If using the FileSystem, you can expect an IOException. If using the Database, you can expect a SQLException. Given this case, how can the customer get away from handling the base Exception and only handle specific exceptions. Also, keep in mind that other storage connections objects can be deployed and plugged into the system in the future.
This reminded me of a favorite rule of Patrick's that use a lot as well.
Simply stated, we say "If your method can't do what it's name promises it can, throw."
If your method is called "Save" and it can't Save, then throw. If it's called DoSomething and it can't DoSomething, throw. The idea is that the method name is a verb and a contract. It's promising to do its best and if it can't do it, it's very likely exceptional.
In this gentleman's example, I figure if you've got a pluggable storage interface underneath, I'd suggest creating a generic "StorageException," and put the actual exception in the InnerException property. However, the point is that it didn't work. Whether the consumer of the Exception cares more than that is a secondary issue.
What are your rules for when to throw and Exception? And please, don't say Exceptions are evil and that HResults should rule the day. Surely the Great .NET Exception Panic of 2001 is over, right? ;)