Inline..
Charles Law said:
Hi Tom
Can you explain why the first exception that is thrown takes a significant
time to execute (several seconds), whilst subsequent exceptions take very
little time?
A number of things happen. First of all, there's always a slight delay
because the exception can be trying to capture the current stack frame. As
for first-time delays, one of the biggest culprits is that most of the core
exception messages are stored as localized resource strings, and the
resource manager has to make sure the correct resource is loaded (could have
to load a DLL) and then locate the text. After that, things are probably
cached.
Whilst I understand what you say about not throwing exceptions for the sake
of it, it offers a convenient third way. I like to think in terms of a
function taking parameters and returning a result, and failure being flagged
by an exception. Why else do we have the InvalidArgumentException exception
(or whatever it's called)? Isn't that just the kind of exception that could
be thrown all the time, if the user insists on entering 99 when the maximum
value permitted is 98?
There's nothing wrong with throwing InvalidArgumentException, but the
calling code (the one with the try-catch) should NEVER depend on an error
for logic branching. Catching exceptions should be... well, an exceptional
case that only happens on a small number of exceptional occasions. The
calling code, if it needs to perform, should make sure it doesn't do
something that could normally cause an exception to take place. Exceptions
should only happen once in a blue moon if all is well (relatively speaking).
Exceptions should not be a lazy coder's alternative to checking things prior
to executing something.
An extreme example of this is the DirectX library for .NET. Most of the
function calls in the .NET library call some unmanaged DirectX code, and
they translate the simple error numbers from the C++ API into .NET
exceptions. But in some cases, like the Render methods that get called
dozens of times (at least) per second, and have a high chance of failing
simply pass the error number back from the method instead of raising the
exception.
How about timeouts? Timeouts with a retry could quite reasonably be
implemented with exceptions, but if there is an overhead then the whole
thing becomes sluggish. If the overhead is caused by the collection of the
stack trace, then I would prefer the default to be to omit the stack trace,
and allow me to specify when it is to be collected. If not, I wonder
what
it
is that takes all the time.
This is fine, but timeouts shouldn't happen during the normal course of
operation. If they happen, something went wrong (and took an unusually long
time to finish). You shouldn't be catching timeout exceptions 20 times a
second, which is where you'd have perf problems
-Rob Teixeira [MVP]