KnowDotNet

Is Your Code Checked?

by William Ryan


When you first start processing data in .NET, there are many nuances to get used to.  Dividing by zero for instance, doesn't always yield a
System.DivideByZeroException.  There are many other nuances, but this is one interesting one that I just came across.  We all know that implicit type conversion is like the most evil thing going since NSync and Barney.  Well, the other day, I was tinkering around trying to encrypt a bit stream and had code that looked something like the following:


int i ;
i = 32766;
//I was in the middle of a loop but it was pushing the upper
         //bounds of what a byte value could hold.

try
{  
  
byte Kaboom = (byte) i;      

}
catch (System.ArithmeticException ex)
{
Debug.Assert(
false, z.ToString());
HandleIt;
}


[Conditional("DEBUG")]
private void HandleIt
{
  
//My handler here..
}

I knew I ran the risk of overrunning the boundary so I caught it in an exception handler.  All was well.  Then the manager of networking came over and tested my application (which was on the PDA).  He came over a few minutes later and asked why things weren't working the way they were supposed to.  The first problem was that I had handlers in place only for Debug...in production, the exception was thrown but I was never notified.  So off I went to figure it out.  Along the way, I found an interesting feature of the way .NET handles Arithmetic Overflow and System.ArithmeticException.

Checked vs. Unchecked:

There are two contexts in which .NET operates in this regard,
checked and unchecked.  In the unchecked context, .NET will overlook the fact that you have arithmetic overflow and won't raise an exception.  In the checked context, it will.

In this example, the code block will execute fine regardless of which Debug/Release mode you compile under:

try
{
unchecked
  {
      
int i ;
       i = 32766;
      
byte NoKaboom = (byte) i;  
   }
}
catch (System.ArithmeticException ex)
{
    Debug.Assert(
false, z.ToString());
}

In this example, your assertion will fail and hopefully you have other code defined to handle it:

try
{
  
checked
  {
      
int i ;
       i = 32766;
      
byte Kaboom = (byte) i;  
   }
}
catch (System.ArithmeticException ex)
{
    Debug.Assert(
false, z.ToString());
      //Better have some other handler if this is built in release
}

Now, just like Debug/Release change the way your program is compiled, you can overload the build options with a /checked+ [for checked to be on by default] or a /checked- [for unchecked to be on by default].

IMHO, specifying this or most any option in the build without explicitly indicating it is a disaster waiting to happen, because someone could rebuild without that option on (not knowing it was built that way originally) and the program will behave completely differently.  You can save some code by leaving out checked/unchecked, but you gain no efficiency in doing so and it hurts readability dramatically.  As such, I'd stick to the explicit declarations.

So why is any of this important?  Well, there are many times you expect that an exception may occur and you trap it, and try to respond accordingly.  Understanding the subtleties of the way .NET processes items like this can give you a lot more control over your program, not to mention help you avoid making mistakes.  Just as I sat there saying "There's no way this can convert and it's not throwing an exception, what's wrong with it.." when the real questions was "It's not working the way I expect it to, what don't I understand"