As far as I can tell, this was a design decision by Microsoft. As a long
time Java programmer, I have come to think it is a good one. It is usually
a bad idea to try to force only a certain type of exception, and in fact it
doesn't work that way in Java anyway. RuntimeExceptions are not checked,
and lots of code can throw things like null-pointer exceptions or divide by
zero exceptions, and Java doesn't catch it. You never see these sorts of
things documented, but they can be thrown all over the place by all sorts of
code.
Usually what happens when you force the users of your library to use
specific exception types is that they have to catch all the Exceptions and
just rethrow them as your exception type, or as a RuntimeException. Silly,
and a waste of effort. Why would I want to wrap a divide-by-zero exception
inside a SocketException, for instance? It just obfuscates the source of
the error.
The other thing that happens is you end up writing stupid exception handlers
for exceptions that are declared but which never happen. If your code is
written in such a way that the exception is never going to occur, you still
have to catch the exception and deal with it because the compiler says so.
I remember that Xerces has one of those for the DocumentFactory, or one of
those objects. You call the function, it works every time. Never, ever
fails. Yet it supposedly could throw an exception, so you have to deal with
a meaningless try catch structure. Silliness.
That one feature in Java has caused as many arguments as whether VB6 can be
considered an OO language.
Let your exceptions run free! It really does work quite well that way.
Document and catch the exceptions you are interested in, and let the rest
bubble up the stack. If they are a problem, the framework will let you
know.