What is the real overhead of try/catch in C#? - c#

So, I know that try/catch does add some overhead and therefore isn't a good way of controlling process flow, but where does this overhead come from and what is its actual impact?

Three points to make here:
Firstly, there is little or NO performance penalty in actually having try-catch blocks in your code. This should not be a consideration when trying to avoid having them in your application. The performance hit only comes into play when an exception is thrown.
When an exception is thrown in addition to the stack unwinding operations etc that take place which others have mentioned you should be aware that a whole bunch of runtime/reflection related stuff happens in order to populate the members of the exception class such as the stack trace object and the various type members etc.
I believe that this is one of the reasons why the general advice if you are going to rethrow the exception is to just throw; rather than throw the exception again or construct a new one as in those cases all of that stack information is regathered whereas in the simple throw it is all preserved.

I'm not an expert in language implementations (so take this with a grain of salt), but I think one of the biggest costs is unwinding the stack and storing it for the stack trace. I suspect this happens only when the exception is thrown (but I don't know), and if so, this would be decently sized hidden cost every time an exception is thrown... so it's not like you are just jumping from one place in the code to another, there is a lot going on.
I don't think it's a problem as long as you are using exceptions for EXCEPTIONAL behavior (so not your typical, expected path through the program).

Are you asking about the overhead of using try/catch/finally when exceptions aren't thrown, or the overhead of using exceptions to control process flow? The latter is somewhat akin to using a stick of dynamite to light a toddler's birthday candle, and the associated overhead falls into the following areas:
You can expect additional cache misses due to the thrown exception accessing resident data not normally in the cache.
You can expect additional page faults due to the thrown exception accessing non-resident code and data not normally in your application's working set.
for example, throwing the exception will require the CLR to find the location of the finally and catch blocks based on the current IP and the return IP of every frame until the exception is handled plus the filter block.
additional construction cost and name resolution in order to create the frames for diagnostic purposes, including reading of metadata etc.
both of the above items typically access "cold" code and data, so hard page faults are probable if you have memory pressure at all:
the CLR tries to put code and data that is used infrequently far from data that is used frequently to improve locality, so this works against you because you're forcing the cold to be hot.
the cost of the hard page faults, if any, will dwarf everything else.
Typical catch situations are often deep, therefore the above effects would tend to be magnified (increasing the likelihood of page faults).
As for the actual impact of the cost, this can vary a lot depending on what else is going on in your code at the time. Jon Skeet has a good summary here, with some useful links. I tend to agree with his statement that if you get to the point where exceptions are significantly hurting your performance, you have problems in terms of your use of exceptions beyond just the performance.

Contrary to theories commonly accepted, try/catch can have significant performance implications, and that's whether an exception is thrown or not!
It disables some automatic optimisations (by design), and in some cases injects debugging code, as you can expect from a debugging aid. There will always be people who disagree with me on this point, but the language requires it and the disassembly shows it so those people are by dictionary definition delusional.
It can impact negatively upon maintenance. This is actually the most significant issue here, but since my last answer (which focused almost entirely on it) was deleted, I'll try to focus on the less significant issue (the micro-optimisation) as opposed to the more significant issue (the macro-optimisation).
The former has been covered in a couple of blog posts by Microsoft MVPs over the years, and I trust you could find them easily yet StackOverflow cares so much about content so I'll provide links to some of them as filler evidence:
Performance implications of try/catch/finally (and part two), by Peter Ritchie explores the optimisations which try/catch/finally disables (and I'll go further into this with quotes from the standard)
Performance Profiling Parse vs. TryParse vs. ConvertTo by Ian Huff states blatantly that "exception handling is very slow" and demonstrates this point by pitting Int.Parse and Int.TryParse against each other... To anyone who insists that TryParse uses try/catch behind the scenes, this ought to shed some light!
There's also this answer which shows the difference between disassembled code with- and without using try/catch.
It seems so obvious that there is an overhead which is blatantly observable in code generation, and that overhead even seems to be acknowledged by people who Microsoft value! Yet I am, repeating the internet...
Yes, there are dozens of extra MSIL instructions for one trivial line of code, and that doesn't even cover the disabled optimisations so technically it's a micro-optimisation.
I posted an answer years ago which got deleted as it focused on the productivity of programmers (the macro-optimisation).
This is unfortunate as no saving of a few nanoseconds here and there of CPU time is likely to make up for many accumulated hours of manual optimisation by humans. Which does your boss pay more for: an hour of your time, or an hour with the computer running? At what point do we pull the plug and admit that it's time to just buy a faster computer?
Clearly, we should be optimising our priorities, not just our code! In my last answer I drew upon the differences between two snippets of code.
Using try/catch:
int x;
try {
x = int.Parse("1234");
}
catch {
return;
}
// some more code here...
Not using try/catch:
int x;
if (int.TryParse("1234", out x) == false) {
return;
}
// some more code here
Consider from the perspective of a maintenance developer, which is more likely to waste your time, if not in profiling/optimisation (covered above) which likely wouldn't even be necessary if it weren't for the try/catch problem, then in scrolling through source code... One of those has four extra lines of boilerplate garbage!
As more and more fields are introduced into a class, all of this boilerplate garbage accumulates (both in source and disassembled code) well beyond reasonable levels. Four extra lines per field, and they're always the same lines... Were we not taught to avoid repeating ourselves? I suppose we could hide the try/catch behind some home-brewed abstraction, but... then we might as well just avoid exceptions (i.e. use Int.TryParse).
This isn't even a complex example; I've seen attempts at instantiating new classes in try/catch. Consider that all of the code inside of the constructor might then be disqualified from certain optimisations that would otherwise be automatically applied by the compiler. What better way to give rise to the theory that the compiler is slow, as opposed to the compiler is doing exactly what it's told to do?
Assuming an exception is thrown by said constructor, and some bug is triggered as a result, the poor maintenance developer then has to track it down. That might not be such an easy task, as unlike the spaghetti code of the goto nightmare, try/catch can cause messes in three dimensions, as it could move up the stack into not just other parts of the same method, but also other classes and methods, all of which will be observed by the maintenance developer, the hard way! Yet we are told that "goto is dangerous", heh!
At the end I mention, try/catch has its benefit which is, it's designed to disable optimisations! It is, if you will, a debugging aid! That's what it was designed for and it's what it should be used as...
I guess that's a positive point too. It can be used to disable optimizations that might otherwise cripple safe, sane message passing algorithms for multithreaded applications, and to catch possible race conditions ;) That's about the only scenario I can think of to use try/catch. Even that has alternatives.
What optimisations do try, catch and finally disable?
A.K.A
How are try, catch and finally useful as debugging aids?
they're write-barriers. This comes from the standard:
12.3.3.13 Try-catch statements
For a statement stmt of the form:
try try-block
catch ( ... ) catch-block-1
...
catch ( ... ) catch-block-n
The definite assignment state of v at the beginning of try-block is the same as the definite assignment state of v at the beginning of stmt.
The definite assignment state of v at the beginning of catch-block-i (for any i) is the same as the definite assignment state of v at the beginning of stmt.
The definite assignment state of v at the end-point of stmt is definitely assigned if (and only if) v is definitely assigned at the end-point of try-block and every catch-block-i (for every i from 1 to n).
In other words, at the beginning of each try statement:
all assignments made to visible objects prior to entering the try statement must be complete, which requires a thread lock for a start, making it useful for debugging race conditions!
the compiler isn't allowed to:
eliminate unused variable assignments which have definitely been assigned to before the try statement
reorganise or coalesce any of it's inner-assignments (i.e. see my first link, if you haven't already done so).
hoist assignments over this barrier, to delay assignment to a variable which it knows won't be used until later (if at all) or to pre-emptively move later assignments forward to make other optimisations possible...
A similar story holds for each catch statement; suppose within your try statement (or a constructor or function it invokes, etc) you assign to that otherwise pointless variable (let's say, garbage=42;), the compiler can't eliminate that statement, no matter how irrelevant it is to the observable behaviour of the program. The assignment needs to have completed before the catch block is entered.
For what it's worth, finally tells a similarly degrading story:
12.3.3.14 Try-finally statements
For a try statement stmt of the form:
try try-block
finally finally-block
• The definite assignment state of v at the beginning of try-block is the same as the definite assignment state of v at the beginning of stmt.
• The definite assignment state of v at the beginning of finally-block is the same as the definite assignment state of v at the beginning of stmt.
• The definite assignment state of v at the end-point of stmt is definitely assigned if (and only if) either:
o v is definitely assigned at the end-point of try-block
o v is definitely assigned at the end-point of finally-block
If a control flow transfer (such as a goto statement) is made that begins within try-block, and ends outside of try-block, then v is also considered definitely assigned on that control flow transfer if v is definitely assigned at the end-point of finally-block. (This is not an only if—if v is definitely assigned for another reason on this control flow transfer, then it is still considered definitely assigned.)
12.3.3.15 Try-catch-finally statements
Definite assignment analysis for a try-catch-finally statement of the form:
try try-block
catch ( ... ) catch-block-1
...
catch ( ... ) catch-block-n
finally finally-block
is done as if the statement were a try-finally statement enclosing a try-catch statement:
try {
try
try-block
catch ( ... ) catch-block-1
...
catch ( ... ) catch-block-n
}
finally finally-block

In my experience the biggest overhead is in actually throwing an exception and handling it. I once worked on a project where code similar to the following was used to check if someone had a right to edit some object. This HasRight() method was used everywhere in the presentation layer, and was often called for 100s of objects.
bool HasRight(string rightName, DomainObject obj) {
try {
CheckRight(rightName, obj);
return true;
}
catch (Exception ex) {
return false;
}
}
void CheckRight(string rightName, DomainObject obj) {
if (!_user.Rights.Contains(rightName))
throw new Exception();
}
When the test database got fuller with test data, this lead to a very visible slowdown while openening new forms etc.
So I refactored it to the following, which - according to later quick 'n dirty measurements - is about 2 orders of magnitude faster:
bool HasRight(string rightName, DomainObject obj) {
return _user.Rights.Contains(rightName);
}
void CheckRight(string rightName, DomainObject obj) {
if (!HasRight(rightName, obj))
throw new Exception();
}
So in short, using exceptions in normal process flow is about two orders of magnitude slower then using similar process flow without exceptions.

Not to mention if it's inside a frequently-called method it may affect the overall behavior of the application.
For example, I consider the use of Int32.Parse as a bad practice in most cases since it throws exceptions for something that can be caught easily otherwise.
So to conclude everything written here:
1) Use try..catch blocks to catch unexpected errors - almost no performance penalty.
2) Don't use exceptions for excepted errors if you can avoid it.

I wrote an article about this a while back because there were a lot of people asking about this at the time. You can find it and the test code at http://www.blackwasp.co.uk/SpeedTestTryCatch.aspx.
The upshot is that there is a tiny amount of overhead for a try/catch block but so small that it should be ignored. However, if you are running try/catch blocks in loops that are executed millions of times, you may want to consider moving the block to outside of the loop if possible.
The key performance issue with try/catch blocks is when you actually catch an exception. This can add a noticeable delay to your application. Of course, when things are going wrong, most developers (and a lot of users) recognise the pause as an exception that is about to happen! The key here is not to use exception handling for normal operations. As the name suggests, they are exceptional and you should do everything you can to avoid them being thrown. You should not use them as part of the expected flow of a program that is functioning correctly.

I made a blog entry about this subject last year.
Check it out. Bottom line is that there is almost no cost for a try block if no exception occurs - and on my laptop, an exception was about 36μs. That might be less than you expected, but keep in mind that those results where on a shallow stack. Also, first exceptions are really slow.

It is vastly easier to write, debug, and maintain code that is free of compiler error messages, code-analysis warning messages, and routine accepted exceptions (particularly exceptions that are thrown in one place and accepted in another). Because it is easier, the code will on average be better written and less buggy.
To me, that programmer and quality overhead is the primary argument against using try-catch for process flow.
The computer overhead of exceptions is insignificant in comparison, and usually tiny in terms of the application's ability to meet real-world performance requirements.

I really like Hafthor's blog post, and to add my two cents to this discussion, I'd like to say that, it's always been easy for me to have the DATA LAYER throw only one type of exception (DataAccessException). This way my BUSINESS LAYER knows what exception to expect and catches it. Then depending on further business rules (i.e. if my business object participates in the workflow etc), I may throw a new exception (BusinessObjectException) or proceed without re/throwing.
I'd say don't hesitate to use try..catch whenever it is necessary and use it wisely!
For example, this method participates in a workflow...
Comments?
public bool DeleteGallery(int id)
{
try
{
using (var transaction = new DbTransactionManager())
{
try
{
transaction.BeginTransaction();
_galleryRepository.DeleteGallery(id, transaction);
_galleryRepository.DeletePictures(id, transaction);
FileManager.DeleteAll(id);
transaction.Commit();
}
catch (DataAccessException ex)
{
Logger.Log(ex);
transaction.Rollback();
throw new BusinessObjectException("Cannot delete gallery. Ensure business rules and try again.", ex);
}
}
}
catch (DbTransactionException ex)
{
Logger.Log(ex);
throw new BusinessObjectException("Cannot delete gallery.", ex);
}
return true;
}

We can read in Programming Languages Pragmatics by Michael L. Scott that the nowadays compilers do not add any overhead in common case, this means, when no exceptions occurs. So every work is made in compile time.
But when an exception is thrown in run-time, compiler needs to perform a binary search to find the correct exception and this will happen for every new throw that you made.
But exceptions are exceptions and this cost is perfectly acceptable. If you try to do Exception Handling without exceptions and use return error codes instead, probably you will need a if statement for every subroutine and this will incur in a really real time overhead. You know a if statement is converted to a few assembly instructions, that will performed every time you enter in your sub-routines.
Sorry about my English, hope that it helps you. This information is based on cited book, for more information refer to Chapter 8.5 Exception Handling.

Let us analyse one of the biggest possible costs of a try/catch block when used where it shouldn't need to be used:
int x;
try {
x = int.Parse("1234");
}
catch {
return;
}
// some more code here...
And here's the one without try/catch:
int x;
if (int.TryParse("1234", out x) == false) {
return;
}
// some more code here
Not counting the insignificant white-space, one might notice that these two equivelant pieces of code are almost exactly the same length in bytes. The latter contains 4 bytes less indentation. Is that a bad thing?
To add insult to injury, a student decides to loop while the input can be parsed as an int. The solution without try/catch might be something like:
while (int.TryParse(...))
{
...
}
But how does this look when using try/catch?
try {
for (;;)
{
x = int.Parse(...);
...
}
}
catch
{
...
}
Try/catch blocks are magical ways of wasting indentation, and we still don't even know the reason it failed! Imagine how the person doing debugging feels, when code continues to execute past a serious logical flaw, rather than halting with a nice obvious exception error. Try/catch blocks are a lazy man's data validation/sanitation.
One of the smaller costs is that try/catch blocks do indeed disable certain optimizations: http://msmvps.com/blogs/peterritchie/archive/2007/06/22/performance-implications-of-try-catch-finally.aspx. I guess that's a positive point too. It can be used to disable optimizations that might otherwise cripple safe, sane message passing algorithms for multithreaded applications, and to catch possible race conditions ;) That's about the only scenario I can think of to use try/catch. Even that has alternatives.

Related

Is it ok to put logic inside exceptions?

I use exceptions extensively, and I often face the dilemma of where to put logic for a very specific exception.
To illustrate let's say that I have implemented my own XML parser which takes a file path, opens the file and parses it. Now in case of parse error I want to throw an exception, which specifies where the incorrect XML is in the file. This is done by outputting message which contains
file name
line number
nearest string contents
Thus far I've been trying to do this by feeding the exception only with scalars, as they may be immediately used in the message. This has become my rule: as little logic as possible inside exceptions. And following that rule any computations of the variables used in exception were located outside that exception.
A simplified example:
void parseXmlFile(string filePath)
{
// …
int line = currentLine();
string surroundingText = StringHelper.getSurroundingText(filePath, offset);
throw new SpecificXmlParseError(filePath, line, surroundingText);
}
But as my project evolved I've had the need to reuse my exception many times. Each time I was forced to compute the same variables over again, which violated the DRY rule. So I wonder if it would be ok to put the computation logic inside the exception and feed it only with the parameters required for computing the data for the message. It could look like this:
class SpecificXmlParseError
{
void SpecificXmlParseError(filePath, offset) : base(ComputeMessage(filePath, offset))
{}
static string ComputeMessage(filePath, offset)
{
int line = computeLineBasedOnOffset(filePath, offset);
string surroundingText = StringHelper.getSurroundingText(filePath, offset);
string exceptionMessage = putTogetherMessage(surroundingText);
return exceptionMessage;
}
// ...
}
The risk here is that the computation logic can throw another exception. But is there a specific reason why this is bad? Only bad thing I can think of is that it would hide the original exception (and the real reason) from any logger that will catch them. But on the other hand the same thing would happen in the first case, where the data is computed before the exception. So are there some additional concerns of which I'm forgetting?
A middle solution would be to write helper class, which would compute the string message. This is the most elegant solution I came up with so far, but it also feels like way to much in this case and violates KISS (after all I just want to throw an exception!).
Is there a win-win solution for this? What are the pros and cons of the solutions?
The risk here is that the computation logic can throw another
exception. But is there a specific reason why this is bad?
Because exception-driven code may be overcomplicated and difficult to understand and thus expensive to maintain.
But in this case (for error handling purposes) I think it is not bad at all.
I believe the first thing you need to do is to log the exception to a log file, or to standard error stream. Then you are sure that original cause of the problem is not lost. Then even if exception handling code fails you still have a chance to investigate.
If your software is mission-critical then I would make sure the error reporting code is bug free - for example, I would cover it with extensive unit tests.
The risk here is that the computation logic can throw another exception. But is there a specific reason why this is bad?
I think throwing another exception is a fact of any exception handling, unless you just stop all execution. It depends on what you want to do. Exception handling has its risks as a paradigm, but you can't eliminate them entirely. I don't think that your alternatives makes the risk any worse. I'm not sure I understand entirely this part of your question.
As for DRY, it suggests creating helper classes to handle errors if you end up with the same logic in the handling. An overarching design principle is "pick your battles" a.k.a. depends on what you value as important. DRY is often in conflict with KISS, but not always. They are rules of thumb. Design is non-deterministic and a problem that is wicked (once you make a decision to solve part of the problem, you've changed the problem). Don't strive to have everything win-win. Strive for acceptable.
Exceptions are a way to detect errors and eventually specify logic on how to handle them. If that logic becomes complex or hard to maintain, then create specialized (highly cohesive) classes for it. In your case of XML parse errors, it's not really that complex (you're just outputting information that is useful for the user to help fix the fault in the XML). I think Grzegorz' answer sums that part up well by saying to just log it.
In the Error Handler (30) pattern in his book Patterns for Fault Tolerant Software, Robert Hanmer says, "Separate error processing code in special handling blocks for easier maintenance and to facilitate new handlers being added in the future." This book has a lot of great advice related to fault-tolerant software patterns.
Your example of reporting information (file name, line number, surrounding text) about the XML error is precisely an example of the Fault Observer (10) pattern from the same book. Users are the "interested observers" of this kind of fault; observers in this pattern don't have to be internal parts of the system.
Convert exceptions is a pattern that's useful where there are layers. It's similar to Hanmer's Escalation (9) pattern.
XML Parsing errors cannot really be recovered by your application. Some approaches help the user try to fix them by guessing. But that is probably overkill for your XML example (not sure how important it is to your problem). If you have an XSD for the input, you can get pretty good validation and useful error messages (but I've never coded it - just used it in IDEs like Eclipse or VisualStudio).

What is the reason of try-catch-rethrow without additional processing in catch block?

Sometimes i meet the following construction exploring ServiceStack's code base:
try
{
...
}
catch (Exception)
{
throw;
}
In my oppinion this construction does nothing. What is the possible reason of doing this?
You're right - it's generally pointless. I have seen people include it so that they can put a break point on the throw line (so they get to see when an exception is thrown, even if they're not breaking on exceptions in general). Unfortunately it often gets left in there after the debugging session has finished.
If you encounter this within a code base you control, I suggest you remove it.
Last time I stumbled over such a construct I asked the author why. Why I was particulary curious was that he did not do this all willy nilly but only in a few places.
His response came with the 'let exceptions be exceptional' which I guess he must have picked up from Eric Lippert where he added that most of his methods would/(should) never throw where in some places his code could throw. By adding the try/catch/throw he was communicating to maintainers that he had recognized that this could happen.
Naturally we try to write code that does not blow up at all. For example by using Code Contracts the number of methods that actually can throw is reduced dramatically.

Exceptions: When to use, timing, overall use

I'll try and ask my question so it doesn't end as a simple argumentative thread.
I've jumped into an application coded in C# recently and I'm discovering the exception mechanism. And I've had a few bad experiences with them such as the following
// _sValue is a string
try
{
return float.Parse(_sValue);
}
catch
{
return 0;
}
I changed it into :
float l_fParsedValue = 0.0f;
if (float.TryParse(_sValue, out l_fParsedValue))
{
return l_fParsedValue;
}
else
{
return 0;
}
Result, my Output in Visual Studio is not anymore flooded with message like
First chance System.FormatException blabla
when string like '-' arrive in the snippet. I think it's cleaner to use the second snippet.
Going a step further, I've often seen that exceptions are too often used ilke: "I do whatever I want in this try-catch, if anything goes wrong, catch.".
Now in order to not get stuck with bad misconceptions, I would like you guys to help me clearly define how/when to use those exceptions and when to stick with old school "if...else".
Thanks in advance for your help!
You should throw exception in exceptional cases. i.e. when something unexpected happens. If you expect a function to regularly throw an exception that's most likely bad design.
In your examples it is very clear that TryParse is better since the exception seems to occor often.
But for example when parsing a file, I expect it to be almost always valid. So I usually use Parse and catch the exception and generate a InvalidDataException with the caught exception as inner exception. Usually simplifies the parsing code a lot, even if it may be bad style.
I recommend Eric Lippers's blog entry: Vexing exceptions
In case of Parse()/TryParse() it's better don't wait for exception, use TryParse and act on incorrect input by yourself.
Exceptions should be used for exceptional behavior, not for flow-control. A basic guideline would be that if normal program flow regularly runs into exceptions you're doing something wrong.
However, it is important to notice that just having a try { } catch { } present will itself not affect performance negatively. Only when an exception is actually thrown and the stack trace needs to be computed you will see (in some cases quite severe) performance degradation.
Another point that hasn't been examined in depth so far is that Exceptions have a cost. They subvert the normal flow of control in the program and there is some resource use as a result.
A simple test would be to write a program that loops over your original float.Parse code with some invalid data, and compare how long it takes to run versus the TryParse version - there will be a small but noticeable difference.
A snippet that sticks in my mind when making decisions about exceptions is from this article:
Almost Rule #1
When deciding if you should throw an
exception, pretend that the throw
statement makes the computer beep 3
times, and sleep for 2 seconds. If
you still want to throw under those
circumstances, go for it.
Programs that use exceptions as part
of their normal processing suffer from
all the readability and
maintainability problems of classic
spaghetti code.
— Andy Hunt and Dave Thomas
I think there is no simple right answer about how/when to use exceptions. It depends on an architecture of the application you're working on and other factors.
I can suggest you to read the chapters 8.3. Error-Handling Techniques and 8.4. Exceptions of the Code Complete book.
Ahh, if only it was that simple! But, alas - the decision when to use exceptions is more often subjective than not. Still, there are guidelines you can use. For example, Microsoft has some.
All in all, the rule of thumb for throwing exceptions is - you only throw an exception when a function cannot do what it was supposed to do. Basically each function has a contract - it has a legal range of input values and a legal range of output values. When the input values are invalid, or it cannot provide the expected output values, you should throw an exception.
Note that there is a slippery point here - should validation (of user input) errors also be thrown as exceptions? Some schools of thought say no (Microsoft included), some say yes. Your call. Each approach has its benefits and drawbacks, and it's up to you to decide how you will structure your code.
A rule of thumb for catching exceptions is - you should only catch exceptions that you can handle. Now, this is also slippery. Is displaying the error message to the user also "handling" it? But what if it's the infamous StackOverflowException or OutOfMemoryException? You can hardly display anything then. And those might not be the only exceptions that can leave the whole system in an unusable state. So again - your call.

Bad Form to use try/catch as a test?

I get the feeling that this is, but I wanted to confirm-
is it bad form to do something like:
try
{
SqlUpload(table);
}
catch(PrimaryKeyException pke)
{
DeleteDuplicatesInTable(table);
SqlUpload(table);
}
catch(Exception ex)
{
Console.Write(ex);
}
Is it better to do this to potentially save on efficiency in case the table doesn't have duplicates, or is it better to run the delete duplicates bit anyway? (I'm assuming conditions where the table will upload as long as there are no duplicates within the table itself). Also, given how try-catch statements impact performance, would it even be faster to do it this way at all?
I apologize for the crude nature of this example, but it was just to illustrate a point.
Exceptions can be used correctly in transaction management, but it is not the case in this example. On my first look, it appeared that this seemed similar to what Linq2Sql's DataContext class does in its call to SubmitChanges(). However, that analogy was incorrect. (Please see at Chris Marisic's comment to my post for an accurate criticism of the comparison).
On exceptions
In general, if there is some issue that is likely to be encountered, you should check for it first. Exceptions should be used when a response is truly "exceptional" (meaning it is unexpected in the context of proper usage). If the proper usage of a function within a completely valid context throws an exception , then you are probably using exceptions incorrectly.
Excerpt from DataContext.SubmitChanges
This code shows an example of the correct usage of exceptions in transaction management.
Note: Just because Microsoft does it, doesn't automatically mean its right. However, their code does have a pretty good track record.
DbTransaction transaction = null;
try
{
try
{
if (this.provider.Connection.State == ConnectionState.Open)
{
this.provider.ClearConnection();
}
if (this.provider.Connection.State == ConnectionState.Closed)
{
this.provider.Connection.Open();
flag = true;
}
transaction = this.provider.Connection.BeginTransaction(IsolationLevel.ReadCommitted);
this.provider.Transaction = transaction;
new ChangeProcessor(this.services, this).SubmitChanges(failureMode);
this.AcceptChanges();
this.provider.ClearConnection();
transaction.Commit();
}
catch
{
if (transaction != null)
{
try
{
transaction.Rollback();
}
catch
{
}
}
throw;
}
return;
}
finally
{
this.provider.Transaction = null;
if (flag)
{
this.provider.Connection.Close();
}
}
}
Yes, this type of code is considered bad form in .NET.
You would be better off writing either code similar to
if(HasPrimaryKeyViolations(table))
DeletePrimaryKeyViolations(table)
SqlUpload(table)
By reading this code I would assume that primary key violations are an exceptional case and not expected - if they are I think you should remove the duplicates beforehand, do not rely on exception handling for an expected case.
In all common languages/interpreters/compilers, exception handling is implemented to have a minimal performance impact when an exception isn't raised -- under the hood, adding an exception handler is usually just pushing a single value onto a stack or something similar. Just adding a try block wont usually have a performance impact.
On the other hand, when an exception is actually raised, things can get very slow very fast. Its the trade-off for being able to add the try block without worrying about worrying, and its usually seen as acceptable, because you only take the performance hit if something unexpected has already gone wrong somewhere else.
So, in theory, if there is a condition that you expect to happen, use an if instead. Its semantically better because it expresses to the reader that the bad condition is probably going to happen from time to time (e.g., user types in some invalid input), while the try expresses something that you hope never happens (the data source is corrupt). As above, its also going to be easier on performance.
Of course, rules are defined by their exceptions (no pun intended). In practice, there are two situations where this becomes the wrong answer:
First, if you are performing a complex operation like parsing a file, and its and all-or-nothing -- if one field in the file is corrupt, you want to bail on the whole operation. Exceptions allow you to jump out of the whole complex process up to an exception handler encapsulating the entire parse. Sure, you could litter the parsing code with checks and return values and checks on the return values -- but its going to be a lot cleaner just to throw the exception and let it rise up to the top of the operation. Even if you expect that the input is going to be bad sometimes, if there isn't a reasonable way to handle the error exactly at the point where the error occurs, use exceptions to let the error rise up to a more appropriate place to handle it. Thats really what exceptions were for in the first place -- getting rid of all that error handling code down in the details, and moving it to one, consolidated, reasonable place.
Second, a library might not let you make the choice. For example, int.TryParse is a good alternative to int.Parse if the input hasn't already been vetted. On the other hand, a library might not have a non-exception-throwing option. In that case, don't brew up your own code to check without exceptions -- though it might be bad form to use exception handling to check for an expected condition, its worse form to duplicate the functionality of the library, just to avoid an exception. Just use the try/catch, and maybe add a snide comment about how you didn't WANT to do it, but the library authors MADE you :).
For your particular example, probably stick with the exception. While exception handling isn't considered 'fast,' its still faster than a round trip to the database; and there isn't going to be a reasonable way to check for that exception without sending the command anyways. Plus, hitting a database in interfacing with an external system -- that in itself is a pretty to good reason to expect the unexpected -- exception handling almost always makes sense when you are leaving your particular controlled environment.
Or, more specifically to your example, you may consider using a stored procedure with a MERGE statement, to use the source data in table to update or insert as appropriate; the update will be a little friendlier on all fronts than doing a delete-then-insert for existing keys.
try catches are expensive on performance, so don't use them as control structures. Instead use triggers at the database level.
One problem is that any exception caused by call of SqlUpload() in the catch block causes the application to crash, because there is no further exception handling.
You'll probably get a few different opinions on this, but mine is that try...catch should be used for things that shouldn't normally happen (although sometimes it's unavoidable). So by that rule, you should ask if the duplicates are in the table by normal execution of the program or if they should not exist given allowable execution of the program.
Just to clarify, I'm saying "normal" usage of the program, not "correct" usage (e.g. when I test it the duplicates don't appear (correct usage) but when the customer uses it they do (perhaps incorrect but normal), so I need to get rid of them). It's more that the duplicates would only appear in a way that the program cannot control (e.g. sometimes someone goes into the database and adds a duplicate row (hopefully not a normal situation)).
Something like duplicate rows, though, is likely a symptom of some other bug, so you shouldn't mask it but try and find the root cause so that the deletion isn't necessary.

try catch bad form?

i think i sort of know the answer to this, but there are always many ways to do things (some of which are clearly wrong :) )...
I have a little recursive function to find an employees manager's id. this is being used in a import script and it may be that the persons immediate manager has left (been disabled) so we need to find that employees (the manager) manager (and so on) so we can assign stuff to them. in case it isn't obvious, the EmployeesToDisable is a generic list of employees that are marked as disabled in this import.
I guess what i am really asking, is : is the overhead associated with catching an exception too much of a trade off to make in this instance. and should i be doing this differently.
this does work fine, but feels like it is bad form..
i have code thus:
private Guid getMyEnabledManagersID(OnlineEmployee e)
{
Employee manager;
try
{
//see if Employee e's manager is in the disabled list.
manager = (from emp in EmployeesToDisable where emp.EmployeeID.Equals(e.ManagerID) select emp).Single();
//yes they are, so need to call this again
return getMyEnabledManagersID(manager);
}
catch
{
return e.ManagerID;
}
}
Leaving aside the recursion, you should perhaps just use SingleOrDefault and test for null. Actually, you probably don't need the full employee object - you can probably suffice with just returning the id (throughout), i.e.
private Guid getMyEnabledManagersID(Guid managerId)
{
var disabled = (from emp in EmployeesToDisable
where emp.EmployeeID == managerId
select (Guid?)emp.ManagerID).SingleOrDefault();
return disabled == null ? managerId : getMyEnabledManagersID(disabled.Value);
}
Actually, the biggest concern I have with the original form is that it isn't specific to the type of exception; it could be "thread abort", "zombie connection", "deadlock", etc.
As others have pointed out never do that. That is a "worst practice". The exception is there to tell you that you have a logic bug in your program. By catching the exception and continuing on, you hide the logic bug.
Only use Single when you know, positively and for sure, that there is exactly one element in the sequence. If there might be other numbers of elements in the list then use First, FirstOrDefault, SingleOrDefault, or write your own sequence operator; it's not hard to do.
The main reasons to not use this worst practice are:
1) As I said, it hides a bug; those exceptions should never be caught because they should never be thrown in a working program. The exceptions are there to help you debug your program, not to control its flow.
2) Using exceptions as control flow like this makes it difficult to debug a program. Debuggers are often configured to stop on any exception, whether it is handled or not. Lots of "expected" exceptions make that harder. Exceptions should never be expected, they should be exceptional; that's why they're called "exceptions".
3) The catch catches everything, including stuff that probably indicates a fatal error that should be reported to the user.
Apart from other answers,
Try/Catch are very costly operations, your simple if statement is faster in terms of performance then expecting a catch and then following the logic.
Try/Catch should not be part of business logic, instead they should only be part of error handling.
You could use FirstOrDefault() instead of Single and handle the returned null value.

Categories