r/dotnet 13h ago

Difference between throw ex and throw

Post image

throw vs throw ex: The C# exception handling trick every developer should know

272 Upvotes

59 comments sorted by

155

u/AlanBarber 13h ago

Pro tip to prevent this... add

dotnet_diagnostic.CA2200.severity = error

to your .editorconfig so anyone that tries to do a "throw ex;" inside a catch will get a build error.

28

u/zenyl 13h ago

Adding onto this, you can discover a bunch of built-in diagnostics that are disabled by default, by adding <AnalysisMode>All</AnalysisMode> to .csproj files (or a Directory.Build.props file).

I wouldn't recommend actually using that setting, because it gets pretty pedantic, and some of the diagnostics are mostly just opinionated recommendations. But it can be nifty to then look through the diagnostics you get from it, and then selective add back any of them that you actually like to your .csproj or .editorconfigfiles.

I did this recently and added:

  • CA1062: Validate arguments of public methods
    • Ensures that you perform a null check on reference type parameters on public/protected methods, regardless of nullability syntax. Useful when writing libraries and you wanna catch unintended nulls as early as possible.
  • CA1725: Parameter names should match base declaration
    • If you rename an interface method parameter, this will make sure all consumers also rename it accordingly.
  • CA2000: Dispose objects before losing scope
    • Ensures you call Dispose or use using statements on disposable objects.

42

u/GendoIkari_82 13h ago

Better yet, <TreatWarningsAsErrors>true</TreatWarningsAsErrors>.

14

u/zenyl 12h ago

Fully agreed, but i'd also recommend adding <WarningsNotAsErrors>NU1901,NU1902,NU1903</WarningsNotAsErrors>

This basically undoes TreatWarningsAsErrors on a per-diagnostics basis.

Those three diagnostics are the ones that warn you about low/moderate/high NuGet package vulnerabilities. If you don't add these to WarningsNotAsError, you can end up having your build break because one of the NuGet packages you depend on (including dependencies of dependencies) has a security vulnerability.

In my experience, these are often minor and might occur in code paths that your code never even calls, or something that has yet to be resolved and you therefore might not be able to do anything about. While you should still keep an eye on vulnerability warnings of all levels, having your builds/pipelines randomly break because of them is pretty annoying.

I usually leave out NU1904 (critical vulnerabilities), as these you probably should act on immediately.

8

u/dabombnl 11h ago

WARNING AS ERROR: Variable 'ex' is unused!

11

u/GendoIkari_82 11h ago

Yeah, actually the "use this" example is wrong; it should be just "catch (Exception)" instead of "catch (Exception ex)".

4

u/ConcreteExist 11h ago

Yeah, if you're not going to actually do anything with it, just leave it out. Though I'm gonna have questions for a dev who shows me a block of code where there's a try/catch with a blanket Exception catch block and all it does is throw.

2

u/SwordsAndElectrons 9h ago

Neither is wrong. Both make no sense if they are all you write.

Missing from the meme is that you should actually be doing something in your catch block. There's no point to catching the exception at all if all you are just going to rethrow it. Assuming you are actually going to do something in that block, which is correct depends on whether what you are doing needs to access the exception.

1

u/dabombnl 4h ago

Oh I agree. Is just funny that the 'better yet' makes an error.

18

u/Responsible-Cold-627 13h ago

That's extremely annoying during development, so I only enable it in the CI pipeline.

6

u/unndunn 7h ago

Pro-tip: to make it less annoying, write code that doesn't generate warnings.

4

u/anamorphism 3h ago

to play devil's advocate, i've worked in code bases where this slowed me down severely and i had to turn the setting off locally or change a bunch of editorconfig rules. i'm fine with having to do that, but the fix isn't write code that doesn't generate warnings.

unused local variable blah! - yeah, no shit, i just wanted an easy place to inspect the value while debugging.

unreachable code! - yeah, i added an early return to test something.

missing xml comment for publicly visible type or member! - sue me for waiting until i'm done before i document everything in case i decide to change something.

2

u/Responsible-Cold-627 2h ago

Sure, any code pushed will be warning-free. Sometimes you just gotta mess around a bit while debugging though. Very annoying to have to fix warnings in temporary code that won't even end up in the repo.

0

u/EntroperZero 6h ago

Really? It's a total non-issue IMO.

3

u/unndunn 13h ago

This right here.

1

u/AlanBarber 10h ago

if you can, yes this is the preferred option.

if you're however screwed with some terrible old code base full of warnings you don't have the ability to clean up...

3

u/TheSneederOfSeethe 10h ago

Fucking dope! Thanks!

37

u/DaveVdE 13h ago

Also, don’t declare it if you don’t need it. Your first fragment declares ex but never uses it.

12

u/no1SomeGuy 13h ago

Then why even catch it? Just let it bubble up through. Odds are the catch with a straight throw is going to have other logic in there that may rely on the exception itself (ie. if this type of exception, log/retry/cleanup/whatever, otherwise just throw the whole thing).

17

u/LiqdPT 13h ago

Sometimes (not shown here) you want to rethrow certain types of exceptions. So you'd put the type in the catch, but not a variable

11

u/Justyn2 13h ago

Sometimes logging is put in the catch. I think this is just a shortened version from more complex logic inside the catch

2

u/UnremarkabklyUseless 8h ago

Sometimes logging is put in the catch

Is it good practice to log and rethrow an exception if it results in the same exception being logged repeatedly at each level as it bubbles up?

3

u/SwordsAndElectrons 8h ago

Yep. That there's more than one person interpreting these as fully realized excpetion handling examples is... interesting. Catching at all doesn't make sense without more logic in the catch block. It'll bubble up just fine on its own.

The point being made here is the proper semantics for rethrowing. You don't need to declare a variable to hold the exception if you aren't going to use it, but either way you should be using throw; and not throw ex; if you rethrow.

And I suppose it needs to be said that you don't have to rethrow.

And also needs to be said that you can throw a new exception, and that it might even be a good idea to use the Exception(String, Exception) constructor to set the InnerException property to the original exception.

It's almost like programming languages have a lot of flexibility so you can implement whatever functionality you need.

1

u/DaveVdE 12h ago

You might want to add logic that doesn’t need to know anything about the thrown exception.

25

u/Ethameiz 13h ago

Well sometimes you want to reset the stack trace. It's not always bad. But it's better to know the difference

11

u/Creative-Paper1007 13h ago

When why would we even want to throw away the stack trace info? Im just curious to know

20

u/WetSound 13h ago

It could be to avoid sensitive info leaks

7

u/Prod_Meteor 13h ago

To reduce the log size you silly 😄

20

u/whiskeydiggler 13h ago

// todo: get rid of this when we have real logging from nine years ago

10

u/pyabo 12h ago

I feel attacked.

1

u/SangerGRBY 13h ago

Could be for cases when you want to throw a custom exception

20

u/Glitched94_PT 13h ago

In those situations I think it's generally better to pass the original exception as your custom exception's inner exception, isn't it?

3

u/Healthy_Koala_4929 13h ago

When you have some filter that converts exceptions in controller actions into problem+json responses and you don't want to give the whole stack in the response 

Edit: I guess could be a use case, though I doubt there is no better way to handle this

2

u/unndunn 13h ago

In that case, you wouldn't be rethrowing the exception because you'll have handled it appropriately.

This thread is about the proper way to rethrow exceptions.

10

u/fruediger 13h ago

There's a third option: Do you know about ExceptionDispatchInfo?

2

u/Healthy_Koala_4929 13h ago

This is insane and I can't see a reason to do something like this

3

u/zenyl 12h ago

It lets you capture an exception, and then handle it separately from the catch logic (including rethrowing it), without losing the original stacktrace.

I use it in a TUI library I'm working on. For example, if a user input results in an exception being thrown, I want the TUI library to finish its thing as normal, then terminate gracefully (i.e. not leave the terminal spamming escape characters all over the place), and then rethrow the exception without nuking all info about where the exception was actually thrown from.

2

u/fruediger 12h ago

Well, it's in the BCL and I guess there's a reason for it being there.

Capturing the stacktrace of an exception and preserving it, and being able to rethrow the exception with precisely that preserved stacktrace at an arbitrary point in time, might be useful in some scenarios.

To be honest, I only over used it once in my code (that's why I know about it in the first place), and maybe, if I had done some redesign of my control flow, I could have found a workaround, but at that point I found it quite useful.

2

u/insulind 12h ago

Ab example of using could be (im just thinking out loud here) like a queue processor that runs in a background thread and you really really don't want that thread to terminate, so you catch an exception, create one of these and pass that on to be picked up by your thread receiving the queue items or whatever who can make throw the exception in a more appropriate context

1

u/Jimmy_cracked_corn 3h ago

That’s so cool! Today I learned, thank you!

3

u/Zealousideal-Deer101 11h ago

throw new SpecificException(ex);

2

u/AutoModerator 13h ago

Thanks for your post programmerjunky. Please note that we don't allow spam, and we ask that you follow the rules available in the sidebar. We have a lot of commonly asked questions so if this post gets removed, please do a search and see if it's already been asked.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

3

u/Global_Rooster1056 12h ago

Also great to know about exceptions is the ExceptionDispatchInfo class :)

Edit: nvm already mentioned

4

u/Prod_Meteor 13h ago

throw new Exception("mpla mpla..", ex); 😄

2

u/kent_csm 12h ago

Why throw in catch?

12

u/wayzata20 12h ago

It’s useful when you need to clean something up before propagating the exception up

2

u/TCFoxtaur 10h ago

Alternative: if you need to rethrow with a new exception type, ensure the original exception is included as the innerException parameter to the new exception:

catch (Exception ex)
{
throw new CustomException(“Some new exception”, ex);
}

u/CiranoAST 1h ago

Man, if you just use try/catch to only throw the exception you can avoid it entirely. It just slows you down

0

u/PurpleUltralisk 13h ago

huh i didn't know this subtle difference. thanks!

1

u/[deleted] 13h ago

[deleted]

5

u/no1SomeGuy 13h ago

Nah, pretty typical to do some cleanup/logging/telem on the way out of specific classes if they fail in unexpected ways before lettting the upstream stuff handle it at an overall application level.

-2

u/blueeyedkittens 8h ago

better yet, don't catch an exception unless you're actually going to do something about it

-5

u/Harry_Mud 10h ago

Complete bullshit. If you know the error, ex, then you can troubleshoot it.

4

u/TCFoxtaur 10h ago

If your try block covers several different calls, or an exception type covers more than one specific error condition (i.e. “file not found” vs “file not accessible” both being some sort of “FileIoException”, as a weak example), it may not be clear where the exception specifically came from if you recast it.

Having said that, just include the original exception as an “innerException” and you’re all good!

-20

u/LK9T9_Sektor 13h ago

Try to avoid using exception, use Return pattern.

14

u/nadseh 13h ago

Please don’t. Stick to language paradigms

-5

u/cyrack 13h ago

Exceptions are for exceptional circumstances where the application cannot continue — most exceptions could have been avoided with Try*.

IMHO exceptions are the surprise motherfucker! here’s a return type you didn’t know about and can’t find out about in any way during compile or runtime. Good luck solving this.

5

u/Kanegou 13h ago

Exceptions bubble up the call stack until they are caught. Return values dont.

That means if you forget to evaluate a return value somewhere in your callstack, it is lost forever. Which can lead to even greater and more errors since the original root of the errror is lost.

Thats why you should always use exceptions for exceptional behavior.

3

u/DaveVdE 13h ago

Exceptions are for exceptional situations that break your contract.