9

In Python, there is this useful exception handling code:

try: # Code that could raise an exception except Exception: # Exception handling else: # Code to execute if the try block DID NOT fail 

I think it's useful to be able to separate the code that could raise and exception from your normal code. In Python, this was possible as shown above, however I can't find anything like it in C#.

Assuming the feature or one like it doesn't exist, is it standard practice to put normal code in the try block or after the catch block?

The reason I ask is because I have the following code:

if (!IsReadOnly) { T newobj; try { newobj = DataPortal.Update<T>(this); List<string> keys = new List<string>(BasicProperties.Keys); foreach (string key in keys) { BasicProperties[key] = newobj.BasicProperties[key]; } } catch (DataPortalException) { // TODO: Implement DataPortal.Update<T>() recovery mechanism } } 

Which requires the normal code to be in the try block because otherwise if an exception was raised and subsequently handled, newobj would be unassigned, but it feels quite unnatural to have this much code in the try block which is unrelated to the DataPortalException. What to do?

Thanks

3
  • 1
    I've always hated using try catch blocks because of this. There's no way to separate did-break code and didn't break code. Commented Mar 3, 2010 at 23:26
  • 1
    Voting to close as exact duplicate: stackoverflow.com/questions/1177438/c-try-catch-else Commented Mar 3, 2010 at 23:35
  • This might be a duplicate, but that question was never answered sufficiently. After reading through the answers, I like Daniel Newby's concept the best. Commented Aug 17, 2012 at 20:53

10 Answers 10

9

I would prefer to see the rest of the code outside the try/catch so it is clear where the exception you are trying to catch is coming from and that you don't accidentally catch an exception that you weren't trying to catch.

I think the closest equivalent to the Python try/catch/else is to use a local boolean variable to remember whether or not an exception was thrown.

bool success; try { foo(); success = true; } catch (MyException) { recover(); success = false; } if (success) { bar(); } 

But if you are doing this, I'd ask why you don't either fully recover from the exception so that you can continue as if there had been success, or else fully abort by returning an error code or even just letting the exception propagate to the caller.

Sign up to request clarification or add additional context in comments.

5 Comments

+1 for the 'handle the exception properly' part. If you can't recover from the exception, you should probably stop doing what you're doing immediately. If you can't get stop gracefully, refactor so you can.
+1, but I have to ask: how is this better than putting the call to bar() right before the catch?
@David: With the code I gave, if the bar function throws a MyException then it will not be caught but with your suggestion it will be caught. The method I showed more closely matches the try: catch: else: construct in that exceptions raised in the else are not caught.
I use this pattern fairly often and I usually initialize success to false - saves me one line of code in the catch block.
Sometimes, it is proper to pre_do; try { do } catch (error) { recover } else { do_more }; post_do;. That does not mean the error was not recovered from or that the code did not full abort what it needed to.
8
+50

Barbaric solution: create an Else class derived from Exception, throw an instance of it at the end of the try block, and use catch (Else) {...} to handle the other stuff.

I feel so dirty.

2 Comments

I don't know what to do here - this demands a -1 vote, but I'm amused enough to hesitate to do so.
Else in python doesn't catch all other exceptions. Else, is only ran when no exceptions are present.
3

C# does not have such a concept, so you are just left with three options,

  • put the else code inside the try.
  • put the else code outside the try catch block, use a local variable to indicate success or failure, and an if block around your else code.
  • put the else code in the finally block, use a local variable to indicate success or failure, and an if block arount you else code.

Comments

3

This will might get downvoted but doesn't c# have goto(note I have almost no c# knowledge so I have no idea if this works).

what about something like

try { ... } catch(Exception ex) { ... goto Jump_past_tryelse } ...//Code to execute if the try block DID NOT fail Jump_past_tryelse: ... 

3 Comments

I almost gave you a +1 simply for offering out the whole pub with your 'goto'!
"offering out the whole pub "==?
@RomanA.Taycher 8 years later, googling "offering out the whole pub" yields exactly 1 search result: this page. I guess we'll never know...
2

Allow me to repeat an idea from a similar StackOverflow question. You cannot do this directly, but you can write a method that encapsulates the behavior you need. Look at the original question to see how to implement the method (if you're not familiar with lambda expressions and Func delegates). The usage could look like this:

TryExceptRaise(() => { // code that can throw exception }, (Exception e) => { // code to run in case of an exception return (...); }, () => { // code to run if there is no exception return (...); }); 

Comments

2

Just put your "else" block before the catch. Then, it will only execute if code execution reaches that point:

try { fee(); fi(); foe(); fum(); /// put your "else" stuff here. /// It will only be executed if fee-fi-foe-fum did not fail. } catch(Exception e) { // handle exception } 

Given that, I fail to see the use of try..catch...else unless there's something vital missing from the OP's description.

6 Comments

The difference is that there's 1 line that's expected to throw an exception and you're expecting that can happen and catching it. If a different line threw the exception that might be something you don't want to catch, because it may indicate an actual bug.
@Davy8 in that case, you should either be a) catching only the specific exception type that you expect, or b) put the code that you don't expect to generate an exception outside of this try..catch block. In any case, you should still be catching any exceptions that occur so that you can fail gracefully.
It's close, but it's not quite equivilent. If it's just outside the try/catch it will execute regardless of whether the first section threw an exception, but it should only execute when the first part did not throw. It is possible that the same exception type could be thrown, so merely catching a specific exception is an improvement, but isn't exactly the same.
@DavidLively: You should not gracefully fail from a bug that should not exist. If some sort of consistency needs to be maintained, the calling code should ensure that and report the error.
@NoctisSkytower As opposed to bugs that should exist? I agree that using exceptions for flow control is bad. If, for instance, you are shipping a library that needs to hide the real exception, leaving logging up to the caller can be unacceptable. There are circumstances - talking to an external device. for instance, where that sort of issue can't be solved by design.
|
1

With C# version 7, you could use local functions to emulate this behaviour:

Example 1: (since C# version 7)

void Main() { void checkedCode() { try { foo(); } catch (Exception ex) { recover(); return; } // ElseCode here } checkedCode(); } 

If you prefer lambda syntax, you could also declare a run method

void Run(Action r) { r(); } 

which only needs to be there once in your code, and then use the pattern for anonymous methods as follows

Example 2: (older C# versions and C# version 7)

Run(() => { try { foo(); } catch (Exception) { recover(); return; } // ElseCode here }); 

whereever you need to enclose code in a safe context.


Try it in DotNetFiddle

using System; public class Program { public static void Main() { var objDemo = new Demo(); objDemo.runWithException = false; objDemo.Example1(); // now the same with exception objDemo.runWithException = true; objDemo.Example1(); Console.WriteLine(); objDemo.runWithException = false; objDemo.Example2(); // now the same with exception objDemo.runWithException = true; objDemo.Example2(); } } public class Demo { public bool runWithException { get; set; } = false; public void Example1() { void checkedCode() { try { foo(); } catch (Exception) { recover(); return; } // ElseCode here Console.WriteLine("Hello from else"); } checkedCode(); } void Run(Action r) { r(); } public void Example2() { Run(() => { try { foo(); } catch (Exception) { recover(); return; } // ElseCode here Console.WriteLine("Hello from else"); }); } public void foo() { Console.WriteLine("Hello from foo()"); if (this.runWithException) throw new ApplicationException("TestException"); } public void recover() { Console.WriteLine("Hello from recover()"); } } 

Notes:

  • In both examples a function context is created so that we can use return; to exit on error.
  • You can find a similar pattern like the one used in Example 2 in JavaScript: Self-invoking anonymous functions (e.g. JQuery uses them). Because in C# you cannot self-invoke, the helper method Run is used.
  • Since Run does not have to be a local function, Example 2 works with older C# versions as well
  • If you want to learn more about Python (more general information), look here.

Comments

0

You could do something like this:

if (!IsReadOnly) { T newobj = null; try { newobj = DataPortal.Update<T>(this); } catch (DataPortalException) { // TODO: Implement DataPortal.Update<T>() recovery mechanism } if (newobj != null) { List<string> keys = new List<string>(BasicProperties.Keys); foreach (string key in keys) { BasicProperties[key] = newobj.BasicProperties[key]; } } } 

Comments

0

that would be the empty statement like hits

try { somethingThatCanThrow(); } catch(Exception ex) { LogException(ex); return; } ContinueFlow(); 

Comments

0
if (!IsReadOnly) { T newobj; bool Done; try { newobj = DataPortal.Update<T>(this); List<string> keys = new List<string>(BasicProperties.Keys); foreach (string key in keys) { BasicProperties[key] = newobj.BasicProperties[key]; } Done = true; } catch (DataPortalException) { // TODO: Implement DataPortal.Update<T>() recovery mechanism Done = false; } finally { if (newobj != null && Done == false) { List<string> keys = new List<string>(BasicProperties.Keys); foreach (string key in keys) { BasicProperties[key] = newobj.BasicProperties[key]; } } } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.