23

Disclaimer: It is well known that catch (ex) { throw ex; } is bad practice. This question is not about that.


While digging through Microsoft reference sources, I noticed the following pattern in a lot of methods:

try {
    ...
} catch {
    throw;
}

No logging, no debugging code—just a plain simple catch { throw; }.

Since, obviously, the guys at Microsoft should be fairly proficient in the use of C#, what could be the point of doing that instead of just omitting the catch block (and the try statement) altogether? Is there a technical reason for coding like this, or is it purely a stylistic choice?

Note: I don't know if it is relevant, but all such instances I could find also contain a try-finally block nested inside the try clause of the try-catch block.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • 12
    The obvious is to allow breakpoints to be set without altering the source and where you want to break in that method on any exception. Which is discussed in [one of the answers](https://stackoverflow.com/a/1443543/15498) to the question you already linked. – Damien_The_Unbeliever Oct 09 '17 at 09:27
  • 4
    *Microsoft should be fairly proficient in the use of C#* Primarily opinion based ;) – Liam Oct 09 '17 at 09:27
  • That force all relevant `finally` blocks to be executed. – user4003407 Oct 09 '17 at 09:29
  • 3
    @PetSerAl `finally` blocks execute regardless of the presence of a `catch` block. – James Thorpe Oct 09 '17 at 09:30
  • Check [this answer](https://stackoverflow.com/a/2728661/7923571) – Ferus7 Oct 09 '17 at 09:35
  • @JamesThorpe AFAIK, .NET do not run any `finally` or `fault` blocks until it find a `catch` to handle exception. Which mean if there are no catch block and exception escape thread root method, then .NET not obligated to run any `finally`/`fault` blocks at all. Also, order of exception filters and `finally` blocks may be relevant if `finally` block do security related staff, like revert impersonation. – user4003407 Oct 09 '17 at 09:50
  • 2
    @PetSerAl: You are wrong. A finally block does not require a catch block to run. There are circumstances where you can't rely on a finally block to be run but those are abnormal things like pulling out the power cable on the computer. See https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-finally for an example of a try...finally which by your thinking would be a pointless construct. – Chris Oct 09 '17 at 09:52
  • Looking at the answers so far they both seem to be speculating on why somebody might write that code which is inherently subjective. It feels like it is currently "Primarily Opinion Based". I'm wondering if it could be modified slightly to ask for specific technical reasons for it but then the answer I suspect is slightly trivial. – Chris Oct 09 '17 at 10:22
  • 3
    @Chris [C# specification](https://github.com/dotnet/csharplang/blob/master/spec/exceptions.md#how-exceptions-are-handled): Once a matching catch clause is found, the system prepares to transfer control to the first statement of the catch clause. Before execution of the catch clause begins, the system first executes, in order, any finally clauses that were associated with try statements more nested that than the one that caught the exception. If no matching catch clause is found, one of two things occurs: – user4003407 Oct 09 '17 at 10:27
  • 3
    If the search for matching catch clauses reaches the code that initially started the thread, then execution of the thread is terminated. The impact of such termination is **implementation-defined**. – user4003407 Oct 09 '17 at 10:28
  • 4
    @Chris Also read your own link: However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. ... Usually, when an unhandled exception ends an application, whether or not the finally block is run is not important. However, if you have statements in a finally block that must be run even in that situation, one solution is to add a catch block to the try-finally statement. – user4003407 Oct 09 '17 at 10:36
  • 2
    @PetSerAl Actually, that's a really good point. Especially when **taken in conjunction with the code that the OP linked to**. These try/catches are wrapped around try/finally blocks. I think that would form the basis of a good answer. – James Thorpe Oct 09 '17 at 10:37
  • 1
    @Heinzi Is it the case that in all the cases you've found this code structure in the reference source, that they're wrapped around a try/finally? The first couple I found in the file you linked to certainly are. – James Thorpe Oct 09 '17 at 10:39
  • 1
    @PetSerAl: Well that will teach me to think I understand something and not read it properly! Thanks for the illumination. :) – Chris Oct 09 '17 at 10:45
  • 1
    @JamesThorpe: Now that you mention it: Yes, all of them are wrapped around a try/finally. Interesting! If PetSerAl's assumption is correct, this would be a very interesting answer. – Heinzi Oct 09 '17 at 12:52
  • @Heinzi May be worth bumping this question with an edit showing that actually rather than asking about the `try{}catch{throw;}` pattern, it turns out it's more specifically the `try{try{}finally{}}catch{throw;}` pattern? I've had a quick look around, and haven't (yet) found another question about it – James Thorpe Oct 10 '17 at 10:07
  • @JamesThorpe: Wouldn't that be more appropriate in the answer? *"`catch {throw;}` makes sense if the try block contains an inner try-finally block, because... /stuff about the C# spec and finalizers/..."*. I don't want to rule out a priori that there might be other possible explanations and the inner try-finally-clause is just a coincidence. I will add a note about your observation, though. – Heinzi Oct 10 '17 at 10:48
  • Maybe - definitely worth noting how it's used in the code you read in the Q though as I think it makes it more tangible than perhaps something that's more opinion based – James Thorpe Oct 10 '17 at 10:49
  • 1
    @JamesThorpe: True, I've added a note. I don't want to expand the code example with the inner try-finally block, because I'm *sure* that this would cause a lot of people to (1) quickly glance at the question and (2) add a completely useless answer explaining the use of `try-finally` inside `try-catch`. ;-) – Heinzi Oct 10 '17 at 10:52
  • Is there any way to figure out if this "design" is all from the same author/developer or maybe from the same "architect" (whomever does code reviews and is allowed to commit overriding changes)? Maybe this person has a bias towards this design because it is their preferred way of debugging or testing edge case scenarios (exceptions)? Too bad there is no way to see a commit history.... – Igor Oct 10 '17 at 11:05
  • 2
    @Amit - It **is** a bad practice. The whole call stack is reset and you lose information that can be vital to debugging the original reason why/where the exception occurred in the first place. Even with a 3rd party class library you should not use `throw ex;`. If you want to abstract the Exception in your own type then throw a new exception and pass the original in as the inner exception. – Igor Oct 10 '17 at 11:07
  • 1
    @Amit That's the whole point. By clobbering the stack trace, `throw ex;` effectively *doesn't* doesn't throw the original exception that happened. To rethrow the original exception that happened, just use `throw;`. –  Oct 10 '17 at 13:47

3 Answers3

12

It affects when exception filters run.

Given

void f() {
  using (var x = AcquireResource()) {
    x.DoSomething();
    x.DoSomethingElse();
  }
}

versus

void f() {
  try {
    using (var x = AcquireResource()) {
      x.DoSomething();
      x.DoSomethingElse();
    }
  } catch {
    throw;
  }
}

with

void g() {
  try {
    f();
  } catch (Exception ex) when (h()) {
    // ...
  }
}

The first version of f would allow the filter h() to be called before x got disposed. The second version of f ensures that x is disposed before external code is run.

In the code you link to, SqlConnectionHolder is used a lot, and catch { throw; } blocks are all around the use of SqlConnectionHolder.

7

As C# Specification describes:

When an exception occurs, the system searches for the nearest catch clause that can handle the exception, as determined by the run-time type of the exception. First, the current method is searched for a lexically enclosing try statement, and the associated catch clauses of the try statement are considered in order. If that fails, the method that called the current method is searched for a lexically enclosing try statement that encloses the point of the call to the current method. This search continues until a catch clause is found that can handle the current exception, by naming an exception class that is of the same class, or a base class, of the run-time type of the exception being thrown. A catch clause that doesn't name an exception class can handle any exception.

Once a matching catch clause is found, the system prepares to transfer control to the first statement of the catch clause. Before execution of the catch clause begins, the system first executes, in order, any finally clauses that were associated with try statements more nested that than the one that caught the exception.

in case of exception runtime first looks for catch clause that can handle it, which involve executing any associated exception filters. Undiscriminating catch block interrupt that search and make all nested finally blocks to be executed immediately.

That can be useful when you want to prevent caller from executing arbitrary code (in form of exception filter) before finally block. For example, when finally block affect security context of current thread.

Also, if exception will not be caught by any catch clause, then it will lead to thread termination. And in that case C# Specification did not provide any guaranty, that any finally block will be executed at all.

If the search for matching catch clauses reaches the code that initially started the thread, then execution of the thread is terminated. The impact of such termination is implementation-defined.

user4003407
  • 21,204
  • 4
  • 50
  • 60
-2

The code you linked is actually a very good example.

In my eyes, one should only use try catch blocks when dealing with things outside of their control, like file systems, external things basically.

In the code you linked the try catch is around the database stuff.

What this means is that by using this way of coding, they make sure there are no leaks, no connections remain open.

If anything goes wrong, such as wrong connection string, missing tables, whatever, the code is going to continue to execute, it will gracefully close the connection as shown in the finally block and it will finally throw meaning it will allow the client of that code to get the proper exception, get the entire stack as well and let them decide what to do when that happens.

To be honest I quite like what they did there.

Andrei Dragotoniu
  • 6,155
  • 3
  • 18
  • 32
  • 1
    Check the comments.This isn't about leaks or normal exception handling. It's about the behaviour of `try/finally` in unexpected situations. – Panagiotis Kanavos Oct 10 '17 at 11:00
  • I am not responding to comments, I am responding to the question the OP asked. If that is no longer meaningful then the question needs to be edited to reflect that. – Andrei Dragotoniu Oct 10 '17 at 11:02
  • Check. The. Comments. Your answer is wrong. The OP is asking why `try/finally` is wrapped in `try/catch`. The answer is that unhandled exceptions may *never* run the code in `finally` – Panagiotis Kanavos Oct 10 '17 at 11:03
  • @AndreiDragotoniu: OP here. I appreciate you answering the question, but the question was specifically about why someone would use `try ... catch { throw; }` instead of just `...`. I am afraid your answer does not address that at all (even if we don't consider the comments). – Heinzi Oct 10 '17 at 11:04
  • In any case, in order to close connections and resources you use `try/finally`, not `try/catch`. The question (and related [C# docs, specification](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-finally)) though shows that `finally` isn't always enough – Panagiotis Kanavos Oct 10 '17 at 11:05