C# 06 Study Notes Errors and exceptions
6.Errors and exceptions
📌Handling errors in old days
In the old days, programmers make a GLOBAL variable. When the method is called, the program is asked to check the GLOBAL variable to see if it is successful.
📌What C# does?
C# use exception
to handle error in a more robust way.
6.1. try-catch
exception
📌try-catch
block
try
{
//the code may have errors
}
catch (Exception ex)
{
//handle the exception
}
📌unhandled exception
The catch mechanism is cascading back(由内向外遍历). If the certain type of exception was still not catch, then it will be unhandled exception.
xxxxxxxxxx
string numStr = "2147483648";
try
{
int num = int.Parse(numStr);
Console.WriteLine(num);
}
catch(FormatException fEx)
{
}
Because the catch
block only handles FormatException
, the number exceeds the maximum which will conduct an OverflowException
.
📌multiple catch
handler
C# supports multiple handlers in light of different exception.
xxxxxxxxxx
string numStr = "2147483648";
try
{
int num = int.Parse(numStr);
Console.WriteLine(num);
}
catch(FormatException fEx)
{
}
catch(OverflowException oEx)
{
}
With these pattern, the preceding code will not only handle FormatException
but also OverflowException
.
📌catch multiple exception all in once
C# provides a robust solution for handling exception which is defined very carefully with an inheritance hierarchies(异常用继承层次结构组织). The following is an example:
Therefore, we could use Exception
to catch any types of exception since it is the great-granddaddy of all exceptions.
xxxxxxxxxx
try
{
}
catch (Exception ex)
{
//this block will handle all kinds of exception
}
📌The order execute the catch
block
Taking the following as an example:
xxxxxxxxxx
try
{
//some code here
}
catch(FormatException fEx)
{
}
catch(OverflowException oEx)
{
}
If the code throw both FormatException
and OverflowException
, the program will only fall in ONE catch
block which is the first catching block!!
📌A great practice ordering the Exception
With preceding demonstration, a general good practice is to handle the specific exception in the head and general exception at the tail.
xxxxxxxxxx
try
{
}
catch(FormatException fEx)
{
}
catch(OverflowException oEx)
{
}
catch(Exception ex)
{
}
📌filtering exception
Although the exception is catch, while you only want to process those errors you are interested. You can:
xxxxxxxxxx
try
{
}
catch(Exception ex) when (errorType == 4)
{
//it will handle errors only if the variable errorType == 4
}
📌Propagating Exception
The propagating exception is nothing else but decide when to handle the exception in which scope.
Propagating exception to outside
xxxxxxxxxx
try
{
ScopeA
{
ScopeB
{
//ERROR
}
}
}
catch
{
//catch ERROR
}
catch right away, no propagation!
xxxxxxxxxx
try
{
ScopeA
{
try
{
ScopeB
{
//ERROR
}
}
catch
{
//catch ERROR
}
}
}
catch
{
}
📄 To conclude, you can either propagate exception or not. It depends on the nature of the app you are building.
6.2. checked
and unchecked
for integer operation
📌integer may overflow silently
You CAN'T notice it is overflowed with
try-catch
xxxxxxxxxx
try
{
int max = int.MaxValue;
Console.WriteLine(max+1);
}
catch(Exception ex)
{
}
There is no errors in console but with -2147483648
as result. That's because C# allows the calculation to overflow silently.
📌Why doesn't C# check overflow?
Because!! Arithmetic operation are everywhere in the program and it is SO BAD for performance if checks every arithmetic operation.
📌How should we catch OverflowException
?
There are 2 methods:
1.Turn on such flag to ask C# compiler to check. (NOT recommend❌)
Right click the Project - Properties - Build - Advanced - [x]Check for arithmetic overflow
2.Use checked
and unchecked
(recommend✔️)
Use the checked
and unchecked
keywords to turn on and off integer arithmetic overflow checking in where you want to check.
📌checked
and unchecked
statement
xxxxxxxxxx
int max = int.MaxValue;
unchecked
{
Console.WriteLine($"Unchecked: {max + 1}");
}
checked
{
Console.WriteLine($"Checked: {max + 1}"); //this will not be printed since it is overflow
}
The output:
xUnchecked: -2147483648
Unhandled Exception: System.OverflowException: Arithmetic operation resulted in an overflow.
📌checked
and unchecked
expression
xxxxxxxxxx
int maxUnchecked = unchecked(int.MaxValue+1); //NO ERROR
int maxChecked = checked(int.MaxValue+1); //ERROR!!!
📌NOT support floating-point
You cannot use the checked
and unchecked
keywords to control floating-point (noninteger) arithmetic. The checked
and unchecked
keywords apply only to integer arithmetic using data types such as int
and long
.
6.3. throw
exception
There are many Exception
that can be throw. Just search and throw!
📌throw
statement
xxxxxxxxxx
if(day==1)
{
}
else if(day==3)
{
}
//..
else if(day==7)
{
}
else
{
//day is in the domain of 1 to 7, now there is no options suitable
throw new ArgumentOutOfRangeException("No such day!");
}
📌throw
expression ⭐️
Suppose:
xxxxxxxxxx
string name;
if(nameField.Text != "")
{
name = nameField.Text;
}
else
{
throw new Exception("No input!");
}
The objective of this statement is to assign value to this variable. Recommend to use ternary operator!
xxxxxxxxxx
string name = nameField.Text != "" ? nameField.Text : throw new Exception("No Input!");
This is more elegant!!
6.4. finally
block
📌What does it do?
A finally
block to ensure that critical code always runs, even if an exception occurs.
📌Example - Dispose file ⭐️
This is very handy dealing with accessing a file. Because you have to make sure Dispose
statement always executes at the end even if an exception occurs. Otherwise the file is occupied.
xxxxxxxxxx
TextReader reader = ...;
//...
try
{
string line = reader.ReadLine();
while (line != null)
{
//...
line = reader.ReadLine();
}
}
finally
{
if (reader != null)
{
reader.Dispose(); //Dispose the file in the end no matter what
}
}