Expert Texture Home Contact me About Subscribe Digipede Connect on LinkedIn rwandering on Twitter rwandering on FriendFeed

The blogged wandering of Robert W. Anderson

Three deficiencies in the C# preprocessor

Here are three things I want the C# preprocessor to do. Together they would better support cross-compilation for different .NET versions. Of course, this means that I really want these for C# / .NET 1.1. Too late for that?

1. Ignore all text in #if‘ed out code. Ideally this would simply ignore all text between the #if and the matching #else or #endif. You may think it already does this, but of course it does not. It looks at all of the preprocessor commands. Why do I care? Well, I want to use #pragma warning disable around some specific method-calls to members we plan to make obsolete. This doesn’t work before C# 2.0, so I would like to #if out these pragmas (and turn off all such warnings globally in those builds too, by the way):

#if !__DOTNET11__
#pragma warning disable 618

Of course, this doesn’t work at all because previous versions of C# choke on the warning pragma. It may be too much to call this one a deficiency, but it sure would be nice if it worked.

2. Allow expressions in #if. See the next one for the reason.

3. Provide compiler-version and .NET version constants. This is kind of obvious, but why do I have to define my own constant (as in the above example)? C++ supports the __CLR_VER constant. Why not C#? I would prefer:

#if __CLR_VER < 2.0
. . . 

Of course, this requires expression evaluation and I’m intentionally blurring the distinction between textual constants and mathematical operators.

There are workarounds to these issues, but handling the warnings properly is kind of thorny. I’m a big believer in clean builds, so I think it is worth the time to implement this, but I sure do wish Microsoft had built this in. My understanding is that cross-compilation was not considered a requirement for VS2005 and MSBuild when it was released — not having this kind of support built into the language is another example of that.



    w7 wrote @ June 14th, 2006 at 10:58 am

Signed, approved, agreed.
What is your recommendation re/ the __CLR_VER issue? I have C# code that needs compiling in VS .NET 2003 and VS .NET 2005, where the latter requires a few tweaks, so I’d like to use conditional compilation just in the very way that you indicated won’t work with the C# preprocessor.

    Robert W. Anderson wrote @ June 14th, 2006 at 7:24 pm

Thanks for the comment.
For cross-compilation, we define a __DOTNET11__ constant in the .NET 1.1 projects. That works OK, aside from my desire to use the new #pragma statement. If you need to get around new preprocessor commands, then the choices become kind of heinous:
1. Encapsulate the new code in .NET-version specific files.
2. Write another pre-processor (or filter out invalid pre-processor statements using regexs).
I’ve done #1 in a couple of cases, and will probably do #2 as we get closer to our next release.

    w7 wrote @ June 14th, 2006 at 11:17 pm

Thanks for your feedback, Robert. #2 should simply read “use another…”, not “write another…”. You should be able to use the standard C/C++ preprocessor as a pre-build step, but I am not totally sure if the C# project can be configed in that way.

With regards to my issue, your suggestions are gratefully received but don’t quite do the trick for me (it’s the same source code, so I cannot define one macro in one source file and another in the second). I guess I’ll follow somebody else’s recommendation to create different build configurations (“Release .NET 2”, “Release .NET 1.1”, etc), and instruct people to use the correct ones.

    Robert W. Anderson wrote @ June 15th, 2006 at 7:16 am

Actually, no, I meant “write another”. I meant something very simplistic that, in my case, would simple remove lines with #pragma warning. I don’t think the C++ pre-processor would do well for this, but maybe it would work.

I didn’t really go into detail on how we do cross-compilation: there is a post-build step run from VS2005 that calls nant that in turn invokes a build for .NET 1.1 from the command-line. This is where hte __DOTNET11__ constant is defined, not in the C# source code.

I actually don’t like the multi-configuration idea: I want both builds every time.


    Reinier Post wrote @ October 19th, 2007 at 4:19 am

(Sorry, retry.)

I *am* using this, but in VB:

#If VBC_VER *lt; 8.0 Then

I came here Googling for the name of the corresponding variable in C#.
(Other people do write code in C#.) Can’t find anything on MSDN.

(It’s small things like these that make me prefer VB.)

    Expert Texture » Perils of #define wrote @ January 9th, 2009 at 9:19 am

[…] couple of years ago, I wrote Three deficiencies in the C# preprocessor.  Those issues still exist, but a good thing about C# is you don’t get the following problem […]

Your comment

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>