Introduction
The tip is aimed to put some light to manage the State of the application during erroneous conditions and exceptions.
Background
If you are writing Class library, which is going to be used by other developers, you should be very conscious while finalizing the approach for the Exception and Error Handling. Special attention is required to maintain the state of the type in all erroneous conditions.
Managing State during Exceptions
A thoughtful design highlights the following points to maintain the state during exceptional conditions:
Use of finally block to recover the state & to cleanup
finally
blocks are the code blocks which are guaranteed to be executed in all conditions. finally
blocks are so useful that C# compiler automatically inserts it in case of lock
, using
, foreach
, etc. statements. It is primarily used for dispose of any object to avoid resource leak. In the following example, a fileStream
is expected to be disposed of in all conditions and it's done in finally
block.
public sealed class ExampleClass {
private void ExampleMethod()
{
FileStream fs = new FileStream(@"C:\mv.txt ", FileMode.Open);
try
{
Console.WriteLine(100 / fs.ReadByte());
}
finally
{
if (fs != null) fs.Dispose();
}
}
}
Recovering from Exception
Spending few extra minutes with your code can help in identifying what all exceptions can be generated by that portion of code. By catching these special types of exceptions in separate catch
blocks will help in handling the exception gracefully. For example in the following code, it’s quite obvious to have divided by zero Exception. Hence a special catch
block is used to handle this specific condition.
public class ExampleClass {
private string ExampleMethod()
{
String result;
FileStream fs = new FileStream(@"C:\mv.txt ", FileMode.Open);
try
{
Console.WriteLine(100 / fs.ReadByte());
}
catch (DivideByZeroException) {
result = "Can Divide by zero"
}
catch (OutOfMemoryException) {
result = "out of memory";
}
finally
{
if (fs != null) fs.Dispose();
}
return result;
}
}
Maintain State in Case of Unrecoverable Exception
In real life, a method calls many other methods to finish up any task. Some methods may succeed and some might fail. For example, let’s say that you’re serializing a set of objects to a disk file. After serializing 10 objects, an exception is thrown. As per exception handling guidelines, every exception is to be throw up to the caller. But what about the disk file state?
Obviously, the state is corrupt when exception occurred. To revert to original state of the disk file in this scenario, one has to back out of partially completed operation as shown in the example. To do this, we have to revert the disk file (in the example below) to the function beginning state.
Note: In this case, I am catching all and any exception and throwing it after recovering the state.
public void SerializeObjectGraph(FileStream fs, IFormatter formatter, Object rootObj)
{ Int64 beforeSerialization = fs.Position;
try {
formatter.Serialize(fs, rootObj);
}
catch { fs.Position = beforeSerialization;
fs.SetLength(fs.Position);
throw;
}
}
Points of Interest
In Exception Handling, it's worth noting that “throw e;
” resets parameters like the Exception.StackWalk
property whereas throw
simply throws the same exception without resetting Exception.StackWalk
.