Skip to main content

C# - Preprocessor Overview [Intermediate]


Did you know that C# actually does have a preprocessor? Probably the most common C# preprocessor directive that you see is the #region directive, and that doesn't even have any impact on the code. Now the preprocessor for C# is nowhere near as powerful as the ones for C and C++ (for instance, no macros), but it does let you do a couple of handy things.

C# actually has almost all the standard preprocessor directives - it just happens to be that the functionality of some of them (specifically the #define directive) is quite reduced. The one notable directive that is missing is #include - and it makes sense that C# wouldn't have it, because C# gets the same sort of functionality from the using statements (although there is the fact that #include refers to files and using refers to assemblies - so they are definitely not equivalent).

So let's start at the beginning: #define and #undef. The directive #define gives you the ability to define a symbol, and #undef lets you un-define it. For instance:
#define MY_SYMBOL

/* Do Stuff */

#undef MY_SYMBOL
 
However, while you can define a symbol, you cannot assign a value to it (which is where that major difference from C/C++ comes into play):
#define MY_SYMBOL 42

//Error: Single-line comment or end-of-line expected
 
So what good is defining a symbol when you can't actually give it a value? Because in C/C++, giving it a value was really the whole point. Well, now that you can't give it a value, the only place to use them are in the #if and #elif directives:
#define SYMBOL_A
#define SYMBOL_B

using System;
public class Foo
{
  static void Main() 
  {
#if (SYMBOL_A && !SYMBOL_B)
    Console.WriteLine("SYMBOL_A!!");
#elif (!SYMBOL_A && SYMBOL_B)
    Console.WriteLine("SYMBOL_B!!");
#elif (SYMBOL_A && SYMBOL_B)
    Console.WriteLine("SYMBOL_A and SYMBOL_B!!");
#else
    Console.WriteLine("Neither!!");
#endif
  }
}
 
That code sample pretty much covers all the craziness that you can do with the conditional directives. This particular code block would end up printing out "SYMBOL_A and SYMBOL_B!!", because both symbols were defined. If, say, I had thrown an #undef in there, we might get something else:
#define SYMBOL_A
#define SYMBOL_B

#undef SYMBOL_A

using System;
public class Foo
{
  static void Main() 
  {
#if (SYMBOL_A && !SYMBOL_B)
    Console.WriteLine("SYMBOL_A!!");
#elif (!SYMBOL_A && SYMBOL_B)
    Console.WriteLine("SYMBOL_B!!");
#elif (SYMBOL_A && SYMBOL_B)
    Console.WriteLine("SYMBOL_A and SYMBOL_B!!");
#else
    Console.WriteLine("Neither!!");
#endif
  }
}
 
Now, this code block would end up printing "SYMBOL_B!!".

But now on to my favorite two directives: #error and #warning. They essentially allow you to inject compile errors and warnings into the code. For example:
using System;

public class Foo
{
  static void Main() 
  {
#error My Best Error Ever!!
#warning A Little Tiny Warning
  }
}

//Error: #error: 'My Best Error Ever!!'
//Warning: #warning: 'A Little Tiny Warning'
 
Simple, and yet quite effective. I use them as almost a to-do list - whenever I'm leaving a section of code that I know is wrong, I'll leave some #error or #warning directives so that the compiler will remind me to come back later and fix it.

Next up: #pragma. The #pragma directive is kind of a catch-all in C/C++, and it is the same here in C#. But there is one #pragma varient that is probably useful to know: #pragma warning.
using System;

public class Foo
{
  static void Main() 
  {
    int foo;
    Console.WriteLine("Hi");
  }
}

//Warning: The variable 'foo' is declared but never used
 
Generally, the code above would throw the warning that you see there. But say you want to ignore that warning - you can use the #pragma warning directive to get rid of it:
using System;

public class Foo
{
  static void Main() 
  {
#pragma warning disable 0168
    int foo;
#pragma warning restore 0168
    Console.WriteLine("Hi");
  }
}
 
Essentially, what that does is disable the warning number CS0168 between the disable and restore directives. You should be careful when using this directive, because if you don't restore the warning, it will be disabled for the rest of the file. This #pragma warning directive is actually quite a bit more powerful than displayed here, and if you'd like to learn more, you should read about it at MSDN.

Well, that concludes a nice overview of C#'s preprocessor directives. We did not cover everything, because some things (like #line) could probably get a whole tutorial on their own. Also, if you would like to know more about what can be done with the #pragma directive, you can check out this MSDNpage (there is a lot of stuff).

Comments

Popular posts from this blog

C# Snippet - Shuffling a Dictionary [Beginner]

Randomizing something can be a daunting task, especially with all the algorithms out there. However, sometimes you just need to shuffle things up, in a simple, yet effective manner. Today we are going to take a quick look at an easy and simple way to randomize a dictionary, which is most likely something that you may be using in a complex application. The tricky thing about ordering dictionaries is that...well they are not ordered to begin with. Typically they are a chaotic collection of key/value pairs. There is no first element or last element, just elements. This is why it is a little tricky to randomize them. Before we get started, we need to build a quick dictionary. For this tutorial, we will be doing an extremely simple string/int dictionary, but rest assured the steps we take can be used for any kind of dictionary you can come up with, no matter what object types you use. Dictionary < String , int > origin = new Dictionary < string , int >(); ...

C# WPF Printing Part 2 - Pagination [Intermediate]

About two weeks ago, we had a tutorial here at SOTC on the basics of printing in WPF . It covered the standard stuff, like popping the print dialog, and what you needed to do to print visuals (both created in XAML and on the fly). But really, that's barely scratching the surface - any decent printing system in pretty much any application needs to be able to do a lot more than that. So today, we are going to take one more baby step forward into the world of printing - we are going to take a look at pagination. The main class that we will need to do pagination is the DocumentPaginator . I mentioned this class very briefly in the previous tutorial, but only in the context of the printing methods on PrintDialog , PrintVisual (which we focused on last time) and PrintDocument (which we will be focusing on today). This PrintDocument function takes a DocumentPaginator to print - and this is why we need to create one. Unfortunately, making a DocumentPaginator is not as easy as...

C# WPF Tutorial - Implementing IScrollInfo [Advanced]

The ScrollViewer in WPF is pretty handy (and quite flexible) - especially when compared to what you had to work with in WinForms ( ScrollableControl ). 98% of the time, I can make the ScrollViewer do what I need it to for the given situation. Those other 2 percent, though, can get kind of hairy. Fortunately, WPF provides the IScrollInfo interface - which is what we will be talking about today. So what is IScrollInfo ? Well, it is a way to take over the logic behind scrolling, while still maintaining the look and feel of the standard ScrollViewer . Now, first off, why in the world would we want to do that? To answer that question, I'm going to take a an example from a tutorial that is over a year old now - Creating a Custom Panel Control . In that tutorial, we created our own custom WPF panel (that animated!). One of the issues with that panel though (and the WPF WrapPanel in general) is that you have to disable the horizontal scrollbar if you put the panel in a ScrollV...