When building a .NET library, what's your exception handling policy? In specific, what's your policy about handling exceptions inside library calls and exposing them to calling code?
For example,
- Would you treat a library function as any other, thus letting all exceptions it can't handle flow out of开发者_如何学JAVA it as-is?
- Would you create a custom exception for that library?
- Would you catch all exceptions and throw the library's exception instead? Would you set the original exception as the library's exception internal exception?
- How would the library dependence on a DB affect your exception-handling policy?
What guidelines and rules would you suggest for exception-handling in a .NET library?
Would you treat a library function as any other, thus letting all exceptions it can't handle flow out of it as-is?
Yes, this is definitely the default strategy.
Would you create a custom exception for that library?
Yes, if callers can conceivably do something about the situation and to do so they need to be able to distinguish the exception from other exceptions. But that's pretty rare.
How would the library dependence on a DB affect your exception-handling policy?
A database dependency might entail exposing settings that let callers specify how the library handles certain exceptions (e.g., MaximumDeadlockRetries
).
Would you catch all exceptions and throw the library's exception instead? Would you set the original exception as the library's exception internal exception?
No, not all exceptions. For specific exceptions, it's remotely possible, though the only case I can think of where I might want to do this is when my library has already tried to handle the exception (as in the database scenario above) and failed.
- I let all exceptions bubble that I think the user may be able to handle. THis is basically stuff I think he should expect to see (IO etc.)
- I wrap all eceptions that I want to rethrow in a more abstract manner. In an O/R mapper I had a "DataAccessException" that got any SQL Exception internally - so the user does not have to deal with their intrinsics. The idea here is that any application may want to know a SQL level exception happened, but can not even bother trying to fix it anyway (thanks to the database being one of many types etc.) - so a wrapper is good.
- I never use generic catch all stuff outside debugging.
- I always have a top level handler (appdomain level - unhandled exception event) to try to show the user an unexpected exception happened and to submit it to support.
Custom exceptions - when they make sense. This is not the case very often thanks to some generic exceptions in the framework.
A library that wraps several different classes that may throw different exceptions should IMHO not allow exceptions from within to percolate out as their original types. Instead, they should be wrapped in a library-specific exception that as clearly as possible relates to the original type of the exception.
For example, MagicDatabaseLibrary might define MagicDatabaseException, which in turn has a few derived exceptions MagicDatabaseTimeoutException, MagicDatabaseAuthenticationException, etc. If an SQL Server database throws an SQL Server Timeout Exception (whatever it's called), that should be wrapped in a MagicDatabaseTimeoutException. Likewise for any other semi-expected exceptions that might occur.
If this is not done, code which calls the library will have no practical choice but to use "Pokemon exception handling" if it is to have any hope of dealing with potential database problems. For example, if calling code is supposed to handle the situation where a user supplies credentials to log into a database and the connection fails, it needs to be able to catch that exception. If the calling code doesn't know what type of exception that will be, there's not much it can do except catch every exception, hope it was a result of an improper credential or something, and present a message to the user saying the connection failed. Not nearly as useful as providing a wrapped exception.
精彩评论