Common Type System—Unhandled Constructor Exceptions


Jump to: navigation, search
Visual C# Tutorials
.NET Framework Tutorials

Common Type System

© 2006 Wiley Publishing Inc.

Unhandled Constructor Exceptions

An unhandled exception from a constructor can occur if the body of a constructor causes an exception to be raised. This is sometimes unavoidable, although it is inconvenient. For example, if you were unable to fully initialize the object, for example because of inconsistent or corrupt state, you would have no other choice but to throw an exception. The alternative would be to pretend everything was OK by returning successfully from the constructor, which could lead to failures later on in the program’s execution. It’s better just to have the program fail as soon as you notice a problem.

The reason that this topic is problematic enough to call out is that, in the face of an exception thrown by a constructor, the caller of your constructor will have no reference to your object. Consider what the IL sequence looks like for the C# code Foo f = new Foo():

newobj instance void Foo::.ctor()
stloc.0

The newobj instruction makes a call to the constructor, leaving the result on the execution stack. stloc.0 stores it in a local slot in the execution stack. But if an exception is raised as a result of the newobj instruction (because of insufficient memory to allocate the object, or because of an unhandled exception thrown from the constructor), the result will never be placed on the stack, and the stloc.0 will never execute because the CLR exception handling behavior will take over. The result is that the variable f will be null.

This can cause some unpredictable behavior. For example, consider a type that allocates resources in its constructor but then throws an exception. Normally, types like this will support the IDisposable interface—explained fully in Chapter 5—so that these resources can be reclaimed deterministically. Such code might look like this:

using (Foo f = new Foo())
{
   // Do something interesting...
}

The semantics of the using statement are such that the variable inside the parenthesis will have its Dispose method called at the end of the block, regardless of whether exit is normal or due to an exception from the block’s body. But if an exception occurs during the call to Foo’s constructor, f will never get assigned a value! The result is that Dispose will never get called, and hopefully f’s finalizer will clean up the resources sometime later on.


Previous_Page_.gif Next_Page_.gif





Personal tools