C
C#3w ago
Faker

Exception Handling in C#

Hello guys, sorry to disturb you all; consider the following code:
C#
try
{
// Step 1: code execution begins
try
{
// Step 2: an exception occurs here
}
finally
{
// Step 4: the system executes the finally code block associated with the try statement where the exception occurred
}

}
catch // Step 3: the system finds a catch clause that can handle the exception
{
// Step 5: the system transfers control to the first line of the catch code block
}
C#
try
{
// Step 1: code execution begins
try
{
// Step 2: an exception occurs here
}
finally
{
// Step 4: the system executes the finally code block associated with the try statement where the exception occurred
}

}
catch // Step 3: the system finds a catch clause that can handle the exception
{
// Step 5: the system transfers control to the first line of the catch code block
}
I have a question. I know that try-catch blocks are used to handle exceptions and the finally block is used to "release" any resource after the catch block has been executed. The finally block is always executed irrespective if their is an error or not. My question is, in the above code, notice the inner try-finally statement doesn't have a catch block. So if their is an error in this try block, what happens? We noticed that their is no catch block in the inner try block, so we start looking in the outer try block? What about the finally block, we don't execute it until we finish scheming in the outer try-block? Does this mean that any catch block will always run before any finally block?
51 Replies
canton7
canton73w ago
You're confusing the implementation details with what you actually see, I think Don't worry about when the runtime goes looking for a catch block. What you see is that things are executed innermost-to-outermost So if an Exception happens in that inner try, the finally block gets run, then the outer catch
cap5lut
cap5lut3w ago
thrown exceptions "bubble" up the call stack (the methods that call method that call methods and so on) the first fitting catch clause will be the point where execution then continues. the finally block will always execute no matter what. this can be a thrown exception, but it could also be a return statement, or simple code flow. the order is always try->catch (if applies)->finally and only after this the code flows like usual. so ur step ordering is wrong.
try
{
try
{
throw new Exception();// #1
}
finally
{
// #2
}
}
catch
{
// #3
}
try
{
try
{
throw new Exception();// #1
}
finally
{
// #2
}
}
catch
{
// #3
}
Faker
FakerOP3w ago
yeah I see, like in the inner try-block, we don't have a catch, so we still executes the finally block. Then we kind of exit the inner try block and the exception is passed to outer block; if outer-block has a correct catch block, we can handle the error?
MODiX
MODiX3w ago
canton7
REPL Result: Success
try
{
try
{
throw new Exception("Kaboom");
}
finally
{
Console.WriteLine("Finally");
}

}
catch
{
Console.WriteLine("Catch");
}
try
{
try
{
throw new Exception("Kaboom");
}
finally
{
Console.WriteLine("Finally");
}

}
catch
{
Console.WriteLine("Catch");
}
Console Output
Finally
Catch
Finally
Catch
Compile: 412.097ms | Execution: 25.565ms | React with ❌ to remove this embed.
cap5lut
cap5lut3w ago
exactly
Faker
FakerOP3w ago
Yep I see, thanks guys ! will come back if I have other questions but should be good for now
canton7
canton73w ago
Cool! Yeah there are implementation details about when the runtime goes looking for a catch block, and that can lead to some odd-looking corner cases, but the bog-standard normal case, like the one in your question, behaves exactly as you'd expect
canton7
canton73w ago
Stack Overflow
C# exception handling finally block before catch block
I am quite confused with how exceptions are getting thrown in C#. If an exception occurs, in the try block, 1.it gets thrown to the catch block, 2. If and only if the catch block catches it the fin...
canton7
canton73w ago
Ah that was it, when clauses are executed before finally blocks
cap5lut
cap5lut3w ago
btw, i really love how u ask questions 🙂 u explain your thoughts and assumptions, not like others that paste code and go like "whats wrong?". so, dont start ur questions with being sorry, we are here to help 😉
canton7
canton73w ago
Yep, seconded: very well-written question
cap5lut
cap5lut3w ago
oh yeah that as well!
canton7
canton73w ago
$close
MODiX
MODiX3w ago
If you have no further questions, please use /close to mark the forum thread as answered
cap5lut
cap5lut3w ago
one little side addition: exceptions should be exceptions, dont use them for normal control flow, they are pretty expensive under the hood performance wise
canton7
canton73w ago
Eh, they're still pretty cheap. People get over-excited about micro-optimisations
Faker
FakerOP3w ago
hmmm what do you mean by not using them for normal control flow pls like not to use them everywhere ?
canton7
canton73w ago
Use them in "exceptional" cases, i.e. when a method couldn't do the thing which its name said it was supposed to do Don't use them for normal, expected cases
cap5lut
cap5lut3w ago
a good example is $tryparse
MODiX
MODiX3w ago
When you don't know if a string is actually a number when handling user input, use int.TryParse (or variants, e.g. double.TryParse)
if (int.TryParse("123", out int number))
{
var total = number + 1;
Console.WriteLine(total); // output: 124
}
if (int.TryParse("123", out int number))
{
var total = number + 1;
Console.WriteLine(total); // output: 124
}
TryParse returns a bool, where true indicates successful parsing. - Avoid int.Parse if you do not know if the value parsed is definitely a number. - Avoid Convert.ToInt32 entirely, this is an older method and Parse should be preferred where you know the string can be parsed. Read more here
canton7
canton73w ago
(But that's more to do with the fact that reasoning about control flow which uses non-local jumps is hard)
cap5lut
cap5lut3w ago
think about it like that. u want to try to open a door, instead of opening the door but if its locked u activate some alarm
Faker
FakerOP3w ago
yep I see, instead of using a try-catch block to give an exception when a file doesn't exist when we try to read it, we can simply use an if-statement instead, it's less overhead ?
Angius
Angius3w ago
Well, you can't just replace try-catch with an if-else But you can check for the file's existence, and read it only if it exists
canton7
canton73w ago
But, that's the prime example of where exceptions are the necessary approach. Check-then-read is a TOCTOU race That's like the no. 1 example of when not to do check-then-read
Angius
Angius3w ago
Fair
canton7
canton73w ago
Time-of-check to time-of-use
In software development, time-of-check to time-of-use (TOCTOU, TOCTTOU or TOC/TOU) is a class of software bugs caused by a race condition involving the checking of the state of a part of a system (such as a security credential) and the use of the results of that check. TOCTOU race conditions are common in Unix between operations on the file sys...
Faker
FakerOP3w ago
ah I see, just read about the TOCTOU, didn't know about that yeah, the when clause can create a "conditional catch block" ? For division by zero for e.g, say we write a block of code where result = num1/num2. Here, we know that num2 can be 0 and if this is the case, we will get a DivisionByZero Exception, so in this case is it better to handle the exception using try catch block or to check if denominator is not 0 before proceeding with the division? I understood that any check made, like when checking if a file exists, an attacker can change contents of the file; is it possibile for the attacker to change what happens in our code also?
Angius
Angius3w ago
In this case, it's better to check * 0 is a valid value, not an exceptional state * It won't cause any race conditions or anything And, just to be clear about TOCTOU, for a code like
var path = ...
if(File.Exists(path))
{
var content = await File.ReadAllTextAsync();
}
var path = ...
if(File.Exists(path))
{
var content = await File.ReadAllTextAsync();
}
to break, the file would have to be deleted within nanoseconds of the check
Faker
FakerOP3w ago
yep I see I think I now have a clearer understanding of exception handling, when it's more appropriate to use it and why, thanks ! $close
MODiX
MODiX3w ago
If you have no further questions, please use /close to mark the forum thread as answered
Faker
FakerOP3w ago
I noticed the catch block sometimes takes in argument and so requires the () but sometimes we omit it, how does it behave with and without the parentheses? Is there a reason to use it without the ()? Because, we can catch any exception using the Exception type, no ? So we can have the following code:
C#

try
{
throw new Exception("Error!");
}
catch
{
Console.WriteLine("An error occurred.");
}


// OR

try
{
throw new Exception("Error!");
}
catch(Exception ex)
{
Console.WriteLine($"An error occurred. {ex.Message}");
}
C#

try
{
throw new Exception("Error!");
}
catch
{
Console.WriteLine("An error occurred.");
}


// OR

try
{
throw new Exception("Error!");
}
catch(Exception ex)
{
Console.WriteLine($"An error occurred. {ex.Message}");
}
We only use the "parameterized" catch block when we need the exception type object?
Angius
Angius3w ago
Basically BTW, if code can throw multiple exceptions, you can have multiple catch blocks
Faker
FakerOP3w ago
In case we have multiple exceptions, the exception that may occur first should have its respective catch block in the first order, like order of catch block matters depending on the order in which the exception can occur ? or well not really because of its type
Angius
Angius3w ago
The exception that occurs. What I mean, is some database query can throw, for example ConflictException or ConnectionWhateverException or DatabaseNotFoundException, and you can catch each of them individually Only one catch block will run, though So if you catch Exception first, it will catch all of them Since all of those types would inherit Exception
Faker
FakerOP3w ago
ahhh I see yep noted, thanks !
Angius
Angius3w ago
Exception-handling statements - throw and try, catch, finally - C# ...
Use the C# throw statement to signal an occurrence of an exception. Use the C# try statements to catch and process exceptions occurred in a block of code.
Angius
Angius3w ago
You can also use when to assert some things about exceptions For example, most databases just throw a generic DatabaseException that has the database's internal exception number stored inside So you can do
catch (DatabaseException e) when (e.Code == 471)
{
// handle conflict
}
catch (DatabaseException e) when (e.Code == 221)
{
// handle connection closed
}
catch (DatabaseException e) when (e.Code == 992)
{
// handle incorrect credentials
}
catch (DatabaseException e) when (e.Code == 471)
{
// handle conflict
}
catch (DatabaseException e) when (e.Code == 221)
{
// handle connection closed
}
catch (DatabaseException e) when (e.Code == 992)
{
// handle incorrect credentials
}
etc
Faker
FakerOP3w ago
yeah, just have a look at the docs, like we use a "subset" of a larger exception type; instead of using the exception name like IndexOutOfRange, their exist a code refering to that exception ?
Angius
Angius3w ago
No, you can't do something like
catch (Exception e) when (e.Code == 772)
catch (Exception e) when (e.Code == 772)
for IndexOutOfRange I just gave an example Exceptions can have any properties you want — they're just classes after all — but are not guaranteed to have any Meaning, it's not some inherent property of exceptions that they all have some numeric code to them It's just the first thing that came to mind, because I had to deal with magic numbers like that when handling NpgSQL lol
Faker
FakerOP3w ago
ahhh I see yep
MODiX
MODiX3w ago
Angius
REPL Result: Success
class MyException(int foo) : Exception
{
public int Foo { get; } = foo;
}

try {
throw new MyException(50);
}
catch (MyException e) when (e.Foo % 2 == 0)
{
Console.WriteLine("Even");
}
catch (MyException e) when (e.Foo % 2 != 0)
{
Console.WriteLine("Odd");
}
class MyException(int foo) : Exception
{
public int Foo { get; } = foo;
}

try {
throw new MyException(50);
}
catch (MyException e) when (e.Foo % 2 == 0)
{
Console.WriteLine("Even");
}
catch (MyException e) when (e.Foo % 2 != 0)
{
Console.WriteLine("Odd");
}
Console Output
Even
Even
Compile: 493.962ms | Execution: 40.208ms | React with ❌ to remove this embed.
Faker
FakerOP3w ago
yep make sense now, thanks !
Angius
Angius3w ago
:Ok:
Faker
FakerOP3w ago
Hello guys, I just started to read about the "throw" keyword which throws an exception by creating a new exception object of a specific type. I was wondering, why is it important to use the throw keyword or where do we use it? what are its use cases pls. Like where would we not being able to use try catch block and need to stick with the throw keyword
cap5lut
cap5lut3w ago
u basically throw an exception when you dont know what to do with that unexpected error eg, File.ReadAllBytes(string path) doesnt know how to handle the unexpected case that the file does not exist. to signal that to the caller, it throws an exception. so its the callers responsibility to handle that error. that might be a closing the application/exiting the process or maybe showing an error dialog, or something completely different throwing an exception is basically "hey something unexpected happened, here is the error, now clean up that mess yourself" there is also one case i didnt mention yet, rethrow, basically u have something like
try
{
DoSomethingThatMightThrow();
}
catch (XyzException)
{
// #
throw;
}
try
{
DoSomethingThatMightThrow();
}
catch (XyzException)
{
// #
throw;
}
basically u want the state of ur class/type to be valid all the time, lets assume the DoSomethingThatMightThrow() method modifies ur internal state. due to the exception that state would become invalid the next time it is used, but catch the exception, fix the internal state to make it valid again, but still provide the caller with the exception of what went wrong
Faker
FakerOP3w ago
Yep I see, I have one question. Consider this code:
C#

static double CalculateSquareRoot(double number)
{
if (number < 0)
{
return -1; // Default value
}

return Math.Sqrt(number);
}
C#

static double CalculateSquareRoot(double number)
{
if (number < 0)
{
return -1; // Default value
}

return Math.Sqrt(number);
}
Here, we want to find the Square Root of a number. What we did is we first check if number is negative. If so, then return a value of -1. Then the caller will check if result is successful or not then adjust its logic. My question is, what is the correct way here, is it better to throw an exception or use simple code logic? Another example would be when checking for the age of a person, like if age is less than 0, raise/throw an exception so that caller can handle it or return some unsuccessful operation number. Does the throw keyword cause performance overhead like the try-catch blocks?
cap5lut
cap5lut3w ago
when to throw exceptions is quite use case dependent. ur math example: this is a bit more complex because the existence of NaN, its a value to indicate that an operation wasnt possible, without throwing. thats because often u have quite complex computations going on there and then check at certain points if its NaN to see if there is a failure (u dont want a try catch block for every division, do ya?) for the age of a person: as with each other, this type should maintain a stable state, because a negative age isnt possible, its the callers fault to provide the wrong values and it should throw an exception (an ArgumentOutOfRangeException in this case)
Faker
FakerOP3w ago
yep we don't want to use try catch block everytimes, same with if logic I guess
cap5lut
cap5lut3w ago
there are in the end 2 kinds of exceptions, one that indicate bugs (like ArgumentException, NullReferenceException) which u usually do not catch (or only catch them to log what went wrong) the other kind is failure that is outside of ur control (eg the internet connection died because ur wifi sucks, or the human ripped out the usb stick while u write to that file) (as a side note, there is actually a third kind of exception: the uncatchable, these u will not see unless u do something unsafe that is close to the system, its the kind of problems where the process itself can not recover from)
Faker
FakerOP3w ago
yeah I see, I now have an overview of try-catch blocks and throw keywords and an idea of how to use them now but still need to practice by applying them, thanks !! will come back if I have further questions but should be okay for now

Did you find this page helpful?