A world apart from the everday ...

Assert.IsTrue(Entries.Count == 0);

July 2006 - Posts

Conditional compilation in C#

This is a feature which may or may not be new to you. I have often used the

#IF DEBUG
...
#ENDIF

Code block to surround certain bits of code that I only want to run under certain conditions.

But actual conditional methods were fairly new to me until very recently so I thought I'd share my experiences regarding this really cool feature with everybody.

Consider the following code snippet;

using System;

 

namespace ConsoleApplication1

{

class Class1

{

[STAThread]

static void Main(string[] args)

{

int i = 10;

int x = 0;

Class2 worker = new Class2();

Console.WriteLine(worker.DivideNumbers(i, x).ToString());

Console.ReadLine();

}

}

 

class Class2

{

public int DivideNumbers(int num1, int num2)

{

try

{

return num1 / num2;

}

catch(Exception ex)

{

HandleErrorDebugging(ex);

HandleErrorNicely(ex);

}

return 0;

}

 

[System.Diagnostics.Conditional("DEBUG")]

private void HandleErrorDebugging(Exception ex)

{

Console.WriteLine("An error occurred: " + ex.Message + Environment.NewLine + ex.StackTrace);

}

 

private void HandleErrorNicely(Exception ex)

{

Console.WriteLine("Ooops! Something has gone pear! Please contact the care bears as I am sure they can assist you.");

}

}

}

 

What do you suppose will happen to the HandleErrorDebugging method if DEBUG is not defined? Well nothing. You might be surprised by that statement but let me explain ... nothing happens to the method, it is compiled into the code regardless of whether or not the DEBUG switch is set.

 

 

So what is the point you say? Well the difference comes in at the point of calling the method. So let's take a look at the IL code produced with DEBUG set and without DEBUG set ...

 

Firstly, with DEBUG on;

  .try

  {

    IL_0000:  ldarg.1

    IL_0001:  ldarg.2

    IL_0002:  div

    IL_0003:  stloc.1

    IL_0004:  leave.s    IL_001b

  }  // end .try

  catch [mscorlib]System.Exception

  {

    IL_0006:  stloc.0

    IL_0007:  ldarg.0

    IL_0008:  ldloc.0

    IL_0009:  call       instance void ConsoleApplication1.Class2::HandleErrorDebugging(class [mscorlib]System.Exception)

    IL_000e:  ldarg.0

    IL_000f:  ldloc.0

    IL_0010:  call       instance void ConsoleApplication1.Class2::HandleErrorNicely(class [mscorlib]System.Exception)

    IL_0015:  leave.s    IL_0017

  }  // end handler

  IL_0017:  ldc.i4.0

  IL_0018:  stloc.1

  IL_0019:  br.s       IL_001b

  IL_001b:  ldloc.1

  IL_001c:  ret

} // end of method Class2::DivideNumbers

 

And secondly, with DEBUG off;

  .try

  {

    IL_0000:  ldarg.1

    IL_0001:  ldarg.2

    IL_0002:  div

    IL_0003:  stloc.1

    IL_0004:  leave.s    IL_0012

  }  // end .try

  catch [mscorlib]System.Exception

  {

    IL_0006:  stloc.0

    IL_0007:  ldarg.0

    IL_0008:  ldloc.0

    IL_0009:  call       instance void ConsoleApplication1.Class2::HandleErrorNicely(class [mscorlib]System.Exception)

    IL_000e:  leave.s    IL_0010

  }  // end handler

  IL_0010:  ldc.i4.0

  IL_0011:  ret

  IL_0012:  ldloc.1

  IL_0013:  ret

} // end of method Class2::DivideNumbers

 

Looking at the differences shown above you can clearly see that the ONLY difference is that when DEBUG is not defined the call to the conditional method is not included.

Why is this you say?

 

Well what would happen if this conditional method was referenced by another assembly?

If the method was removed by the compiler then this would have an effect on the compilation of the other assembly.

 

So what does happen in this scenario?

 

  1. App built as Debug using Library built as Debug  -->
  2. The HandleDebug & HandleNicely methods are called.
  3. App built as Release using Library built as Debug -->
  4. The HandleDebug method is NOT called.
  5. App built as Debug using Library built as Release -->
  6. Same as scenario 1.
  7. App built as Release using Library built as Release -->
  8. Same as scenario 2.

 

Proof then that it is the calling assembly's compilation method that determines which conditional methods are called. This is made possible by the fact that the C# compiler creates the conditional methods regardless of whether it was run under Debug or as Release.

 

Where this all gets really interesting is when you introduce inheritance into the equation ...

 

Consider the following code snippet;

using System; 
using System.Diagnostics; 
class Class1  
{ 
   [Conditional("DEBUG")] 
   public virtual void M() { 
      Console.WriteLine("Class1.M executed"); 
   } 
} 

using System; 
class Class2: Class1 
{ 
   public override void M() { 
      Console.WriteLine("Class2.M executed"); 
      base.M();       // base.M is not called! 
   } 
} 

#define DEBUG 
using System; 
class Class3 
{ 
   public static void Test() { 
      Class2 c = new Class2(); 
      c.M();              // M is called 
   } 
}
  

Class2 includes a call to the M defined in its base class. This call is omitted because the base method is conditional based on the presence of the symbol DEBUG, which is undefined. Thus, the method writes to the console "Class2.M executed" only.

 

Subtle!

 

Therefore it is important when using conditional statements to REALLY understand when the call is omitted and when it is not, else all sorts of hassles can creep into your code.

 

If you remember one thing about conditional methods it should be this;

 

Inclusion or exclusion of a call to a conditional method is controlled by the conditional compilation symbols AT THE POINT OF THE CALL!

 

That's it from me for now ... happy conditional programming.

Posted: Jul 03 2006, 09:19 AM by Ryan CrawCour | with no comments
Filed under:
How many accidents will it take ...

After putting the debacle of the past couple of days behind me I have once again become enthralled with the greatest race on earth. The Tour de France is bigger than some silly drug scandal, and it will survive and continue to be the greatest spectacle on this planet.

One thing that I simply cannot understand about the Tour though are the fans. Yes they are passionate, and yes they want to be as close to the action as they can be ... but simply put they are a menace! A danger to the cyclists that are putting everything on the line for victory!

How many times have we seen fans getting in the way?

About 10 years ago one of the worst crashes I have witnessed was a result of a fan trying to take a photo of the bunch approcahing at 70+ km/h. Misjudging the distance and rate of approach the spectator got in the way and single handedly caused a crash that removed 5 top sprinters from the event; arguably also ending the career of one of the greatest sprinters of all times.

Two years ago a spectator got in the way of Lance Armstrong. Armstrong's handle bars hooked on a bag a spectator was waving in the road as they came past. Lance went down. Luckily he got back up and seemed unhurt by the incident.

And now today, Thor sprinting up the final 300m in the yellow jersey get's his arm slashed open by a stupid idiot waving a flag in the road.

All too often hundreds of fans crowd on to the road, run alongside riders, spray them with water, etc. etc. As a rider myself I know how distracting this can be, and certainly very very dangerous!

Come on guys!

ASO, instead of going on a massive witch hunt like you are, how about doing something to protect the riders of your fine race!?!?! Ban the crowds from going near the road. Put up barriers keeping them off the road. etc.

Enuff said .... back to the racing ...

Go Valverde go!

Posted: Jul 02 2006, 07:11 PM by Ryan CrawCour | with no comments
Filed under:
Threads vs Processes ... what is the difference?

So I was recently asked by another developer what the difference between a process and a thread was ...

Easy, I thought and launched into a technical explanation of the wonderful Windows Internal and about shared memory and this and that and so forth ...

Soon though I realised I had completely lost him ... maybe it was the completely blank look on his face that gave me some clue, I'm not sure; but the fact remained I was not helping and was confusing him more than he was before.

So good old Google to the rescue once again.

Enter "Process vs Thread" and because I wasn't exactly "Feeling lucky" I watched hundreds and hundreds and hundreds and posts being churned out.

Post after post claimed to have the real answer, but none of them were able to tell it to me as if I were a baker and not a programmer. (nothing wrong with bakers btw. especially when they provide me my daily dose of chocolate croissants)

Finally I saw something that caught my eye;

My grandmother and the difference between processes and threads

This guy is brilliant! He has managed to break down something quite technical and obscure into a language any self respecting gangster (and grandmother too hopefully) would be able to grasp without difficulty.

Go check it out ... 

I loved it! It's been a while since I laughed about Process and Threads. Wink [;)]