Why doesn't C# support #define macros?

Why doesn't C# support #define macros?

Rate This
  • Comments 37

In C++, I can define a macro such as:

#define PRODUCT(x, y, z) x * y * z

and then use it in code:

int a = PRODUCT(3, 2, 1);

C# doesn't allow you to do this. Why?

There are a few reasons why. The first is one of readability.

One of our main design goals for C# is to keep the code very readable. Having the ability to write macros gives the programmer the ability to create their own language - one that doesn't necessarily bear any relation to what the code underneath. To understand what the code does, the user must not only understand how the language works, but he must also understand all of the #define macros that are in effect at that point in time. That makes code much harder to read.

In C#, you can use methods instead of macros, and in most cases, the JIT will inline them, giving you the same performance aspect.

There's also a somewhat more subtle issue. Macros are done textually, which means if I write:

int y = PRODUCT (1 + 2, 3 + 4, 5 + 6)

I would expect to get something that gives me 3 * 7 *11 = 231, but in fact, the expansion as I've defined it gives:

int y = 1 + 2 * 3 + 4 * 5 + 6;

which gives me 33. I can get around that by a judicious application of parenthesis, but its very easy to write a macro that works in some situations and not in others.

Although C# doesn't strictly speaking have a pre-processor, it does have conditional compilation symbols which can be used to affect compilation. These can be defined within code or with parameters to the compiler. The "pre-processing" directives in C# (named solely for consistency with C/C++, despite there being no separate pre-processing step) are (text taken from the ECMA specification):

#define and #undef
Used to define and undefine conditional compilation symbols
#if, #elif, #else and #endif
Used to conditionally skip sections of source code
#line
Used to control line numbers emitted for errors and warnings.
#error and #warning
Used to issue errors and warnings.
#region and #endregion
Used to explicitly mark sections of source code.

See section 9.5 of the ECMA specification for more information on the above. Conditional compilation can also be achieved using the Conditional attribute on a method, so that calls to the method will only be compiled when the appropriate symbol is defined. See section 24.4.2 of the ECMA specifcation for more information on this.

Author: Eric Gunnerson]

Leave a Comment
  • Please add 1 and 6 and type the answer here:
  • Post
  • Yeah, it's pretty frustrating when someone tries to tell you how to write your code and what to use and not to... Welcome to China :) C# favors readability of the code over the speed of compiled executables, and that is why the resulting modules are so much slower and bloated than the ones written in C/C++. I am missing Macros BIG TIME!

  • Compile-time macros, man, compile-time.  I have to explicitly specify a set of constructors for every class I derive from my base class.  I want to just say "CONSTRUCTORS_DEF()" or something instead of writing it out every time.  I love C#, but something designed to be convenient should allow for something as basic as macros.  Your job isn't to force me to code a certain way.  I don't need to learn structure -- that's what PASCAL was for.

    If you want a greater number of serious developers to move over to C# then you will trust them to code properly.  If you need to have a "C# in dummy mode", then fine, have a compile-time option that disables macros.  Or even, let the class specify if it can be used in macros or not -- then it's up to the DEVELOPER.

    I've been coding since I was 8 on a Commodore 64.  I know how to structure my code, so who the heck are you to tell me what's "clean" code and what isn't?  This is the kind of thing right-wingnuts think we're doing with regulations.  Like regulations, sometimes you need to force developers to code a certain way.  However, not including something as basic as macros because we're "not responsible enough to write clean code" is pretty much the definition of the "Broccoli argument" (look it up).

    Really insulting reason, to be honest.

  • A long explanation instead of just - "we just cannot do this in C# "  ))))

  • Any tool, when abused, can produce bad results (e.g. chainsaws, etc.)  That is no reason to outlaw chainsaws, however. The answer is to train the operator property, since chainsaws have many beneficial uses.

    The lack of macros means that I can no longer do the equivalent of the following

    #if defined(__DEBUG)

    #define DEBUGPRINT(x) printf(x)

    #else

    #define DEBUGPRINT(x)

    #endif

    Sure, I could replace DEBUGPRINT with a function whose body was empty if __DEBUG was not defined, but the compiler would still have to generate code to evaluate the arguments every time, whether in debug mode or not, and evaluating the arguments could be arbitrarily long and complex. With the macro, the entrie DEBUGPRINT invocation, and its argument evaluation, simply go away.

  • Using macros wisely can significantly improve READABILITY.

    I have bunch of fields with the same attributes:

           private DateTime? _someAtt;

           [DbType( "smalldatetime" )]

           [NullValue( typeof( DateTime ), "1/1/0001 12:00:00 AM" )]

           [DevExpress.Persistent.Base.VisibleInDetailViewAttribute( true )]

           [DevExpress.Persistent.Base.VisibleInListViewAttribute( false )]

           [DevExpress.Persistent.Base.VisibleInLookupListViewAttribute( false )]

           public System.DateTime? SomeAtt

           {

               get

               {

                   return _someAtt;

               }

               set

               {

                   SetPropertyValue( "SomeAtt", ref _someAtt, value );

               }

           }

    which I have to repeat over and over and again... With help of macro I would easily define and use one line:

    DEF_MYPROP( DateTime, SomeAtt )

    now don't tell me MACROS are evil

  • If #define macro expansion was omitted from C# because of potential misuse, then I would guess that MOST of the features of C# should be omitted for the same reason. Potential for misuse is not a very good criteria for language features.

  • "The first is one of readability." - I'm very sorry, but this is *very* subjective - and not at all to not support c++ like macros in c#. We use c++ macros in a very big application (build time is more than 12h…) - and macros are readable and easy to use. You just need to know how to use it. As almost everything related to programming so that it is readable.

    Kind regards, Tom

Page 3 of 3 (37 items) 123