Abstract
This article talks about best practices of exception handling, and guides you for some common programming mistakes developers do, as that seems appropriate in most applications written.
Best practices are only guidelines and do not enforce you to follow these, but if followed correctly then you won't only write less lines of code, but you work and code with more logical approach of coding and designing the code modules.
#1 Do Not Throw Exceptions to Control Application Flow
Scenario
The following code throws an exception inappropriately, when a supplied product is not found.
public static void CheckProductExists(int ProductId)
{
//... search for Product
if (ProductId == 0) // no record found throw error
{
throw (new Exception("Product is Not found in inventory"));
}
else
{
Console.WriteLine("Product is available");
}
}
static void Main(string[] args)
{
Console.WriteLine("Enter a ProductId you would like to search [1 โ 100]");
int productId = Int32.Parse(Console.ReadLine());
CheckProductExists(productId);
Console.ReadLine();
}
After execution of Main, and when 0 is passed as shown in Figure 1-1 below.
Figure 1-1 Reading productId from Console
The value being passed to the program as shown in Figure 1-1 will result in an exception as shown in Figure 1-2 below.
Figure 1-2 Throwing exception when ProductId is 0 (Zero)
Problem
Throwing an exception as shown in Scenario section and Figures 1-1 and 1-2 is expensive; presumably throwing an exception causes the CPU to fetch code and data it would otherwise not have executed. You probably should not throw any exceptions in that scenario.
Solution
Consider the possibility that the code shown above not finding a product is an expected condition. Hence, re-factor the code to return a value that indicates the search result after the method's execution. The following code re-writes the code to verify the availability of the product in inventory and sets a flag to true or false.
This apparently avoids a new exception being thrown. The calling code uses a flag value to identify whether the inventory has the specified product or not.
public static bool CheckProductExists(int productId)
{
//... search for Product
if (productId == 0) // no record found
{
return false;
}
else
{
return true;
}
}
static void Main(string[] args)
{
Console.Write("Enter a ProductId you would like to search [1 โ 100] : ");
int productId = Int32.Parse(Console.ReadLine());
if (!CheckProductExists(productId) == false)
{
Console.WriteLine("Found");
}
else
{
Console.WriteLine("Not Available");
}
Console.ReadLine();
}
#2 Use Validation Code to Reduce Unnecessary Exceptions
Scenario
Using a try/catch block can be a very handy solution for most programming situations, for example the most commonly known is DivideByZero. The following code uses a try/catch block to handle DivideByZero and that is pretty convincing.
static void Main(string[] args)
{
Console.Write("Enter numerator : ");
int numerator = Int32.Parse(Console.ReadLine());
Console.Write("Enter divisor : ");
int divisor = Int32.Parse(Console.ReadLine());
try
{
double result = numerator / divisor;
Console.WriteLine(result);
}
catch (DivideByZeroException ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
Figure 1-3 Used try/catch to handle exception
Problem
There is no need to perform exception handling if we can use the basic validation techniques before code is executed. In this scenario an exception only needs to be handled if the divisor is 0 (zero) otherwise it should work fine.
Solution
Let's re-factor the code and rewrite it so try/catch blocks can be avoided, and as a result is more efficient.
static void Main(string[] args)
{
Console.Write("Enter nemerator : ");
int numerator = Int32.Parse(Console.ReadLine());
Console.Write("Enter divisor : ");
int divisor = Int32.Parse(Console.ReadLine());
if (divisor != 0)
{
Console.WriteLine(numerator / divisor);
}
else
{
Console.WriteLine(Double.NaN);
}
Console.ReadLine();
}
Figure 1-4 Using validation code instead to avoid try/catch to handle an exception