82

Is C# able to define macros as is done in the C programming language with pre-processor statements? I would like to simplify regular typing of certain repeating statements such as the following:

Console.WriteLine("foo");
2
  • 33
    By the way, for this particular method you can write cw in Visual Studio and press Tab. Mar 1, 2013 at 20:31
  • 2
    There is a Lisp-style macro processor for C# called LeMP; Lisp-style macros are much superior to C/C++ macros. But in new versions of C# you can shorten Console.WriteLine to WriteLine after adding using static System.Console; at the top of a source file.
    – Qwertie
    Jul 19, 2018 at 3:17

9 Answers 9

62

No, C# does not support preprocessor macros like C. Visual Studio on the other hand has snippets. Visual Studio's snippets are a feature of the IDE and are expanded in the editor rather than replaced in the code on compilation by a preprocessor.

16
  • 89
    @weberc2 Macros are very helpful when the same code base has to target multiple compile-time targets such as iOS, Android, MacOSX, etc. The lack of macros means that you have to put a lot of code between #if/#elseif/#else pragmas when with some simple macros one could emit the proper code for each target in an efficient/elegant and maintainable way. In short, C style macros are very helpful when you have to include code that simply will not compile on some targets. Aug 29, 2013 at 22:42
  • 4
    @JohnnyLambada The better solution is to abstract your platform-dependent code behind a common interface and use CMake and friends to make sure the correct code gets compiled for a given target. Hell, you can even do that in C.
    – weberc2
    Sep 3, 2013 at 4:29
  • 23
    @weberc2 The problem with this 'better solution' is that it's heavy and spreads what could be a few simple lines of code over multiple files which must all be understood to understand the complete solution. I don't agree that that is better. Yes, the C preprocessor was abused to the point of torment (I was definitely an abuser!), but it was also very useful in many situations to make code much simpler and easier to understand. Sep 3, 2013 at 18:12
  • 8
    @weberc2 We're talking about two different things. I'm not saying that a bunch of #ifdefs surrounding large blocks of code is good. It's not. I'm saying that judicial use of #define MACRO(x,y) embedded within #ifdef PLATFORM1 #elif PLATFORM2 ... can be useful in limited cases as a tool in the toolbox. Perhaps you disagree with this as well -- after doing a google search in defense of the preprocessor seems most of the world does as well. But I did come across this gem. Sep 4, 2013 at 14:29
  • 5
    @JohnnyLambada If you really want to use a preprocessor while minimizing your pain, don't define a macro with your platform logic or you'll have to deal with debugging/reading that macro all over your code base. Instead, in as few files as practical, define functions that encapsulate your preprocessor logic so you don't have to worry about it everywhere else. However, it's still better to use your build system to conditionally compile files rather than a preprocessor.
    – weberc2
    Sep 4, 2013 at 15:16
54

You can use a C preprocessor (like mcpp) and rig it into your .csproj file. Then you chnage "build action" on your source file from Compile to Preprocess or whatever you call it. Just add BeforBuild to your .csproj like this:

  <Target Name="BeforeBuild" Inputs="@(Preprocess)" Outputs="@(Preprocess->'%(Filename)_P.cs')">
<Exec Command="..\Bin\cpp.exe @(Preprocess) -P -o %(RelativeDir)%(Filename)_P.cs" />
<CreateItem Include="@(Preprocess->'%(RelativeDir)%(Filename)_P.cs')">
  <Output TaskParameter="Include" ItemName="Compile" />
</CreateItem>

You may have to manually change Compile to Preprocess on at least one file (in a text editor) - then the "Preprocess" option should be available for selection in Visual Studio.

I know that macros are heavily overused and misused but removing them completely is equally bad if not worse. A classic example of macro usage would be NotifyPropertyChanged. Every programmer who had to rewrite this code by hand thousands of times knows how painful it is without macros.

7
  • 23
    You have to get some credit for an 'innovative' solution, and for thinking outside the box. But just a word of advice to anyone reading this 'solution', please don't do it. There are some things that are just wrong, that are such a hack. This is one of those things.
    – danpalmer
    Jul 30, 2013 at 8:55
  • 17
    @danpalmer Why would adding a CPP shellout to MyCommon.targets be just wrong? There are just some things that CPP can do that the language makes incredibly difficult. IMO, it is worse that the developer has to actually manually stringify an argument name when writing throw new ArgumentNullException("argumentName");. Code contracts was supposed to solve that, but it requires an IL rewriter bolted on using .targets, should be no worse to bolt on a CPP call.
    – binki
    Feb 11, 2014 at 22:10
  • 2
    Until C# will implement macros, this is by far the best solution, in fact, a no brainer, a bull's eye shot. I can't qualify this enough. The fact that it's not used by the majority has nothing to do with it being the perfect solution. BTW, IMHO this should be the adopted ubiquitously.
    – mireazma
    Jan 9, 2018 at 20:38
  • 2
    @mireazma Intellisense stops working though. So it's not quite a no brainer Sep 5, 2020 at 16:59
  • 1
    Is there a way to make Intellisense still work with this?
    – JamesHoux
    Oct 29, 2020 at 3:14
37

I use this to avoid Console.WriteLine(...):

public static void Cout(this string str, params object[] args) { 
    Console.WriteLine(str, args);
}

and then you can use the following:

"line 1".Cout();
"This {0} is an {1}".Cout("sentence", "example");

it's concise and kindof funky.

10
  • 2
    So you don't have to type Console.WriteLine(...) (which is pretty long to have to type frequently). You could write your own method to do this but using a string extension is a little more elegant IMHO. Aug 26, 2013 at 3:34
  • 10
    It's not long if you use tab-completion. You're creating two ways of doing the exact same thing, which confuses other developers. Further, it's not more elegant; you might see this sort of thing in Python, but it's weird in C#.
    – mpen
    Aug 26, 2013 at 3:39
  • 4
    +1 for making an extension method. Although... since C# isn't C++, I might personally call it something like .ToConsole() instead of Cout(). Granted, the "C" in "Cout" means console, and .ToConsole() is longer, but .ToConsole() is also a more common general .NET pattern and probably makes more sense to somebody not coming from a C++ background, and Intellisense will pick it up and let you just type .ToC and hit the spacebar to complete it, anyway. Apr 16, 2014 at 18:29
  • 4
    -1: Not only is this a very specific use-case that cannot be easily applied generally, but it's also not even a case where Preprocessor Macros are warranted.
    – marknuzz
    May 28, 2014 at 6:12
  • 7
    This is not a preprocessor macro. The solution to this question clearly states: "C# does not support preprocessor macros like c" May 28, 2014 at 20:39
14

While you can't write macros, when it comes to simplifying things like your example, C# 6.0 now offers static usings. Here's the example Martin Pernica gave on his Medium article:

using static System.Console; // Note the static keyword

namespace CoolCSharp6Features
{
  public class Program
  {
    public static int Main(string[] args)
    {
      WriteLine("Hellow World without Console class name prefix!");

      return 0;
    }
  }
}
1
  • 1
    Damn, this doesn't solve my need for macros but sure is really useful. Thank you! Oct 18, 2023 at 21:40
10

There is no direct equivalent to C-style macros in C#, but inlined static methods - with or without #if/#elseif/#else pragmas - is the closest you can get:

        /// <summary>
        /// Prints a message when in debug mode
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe void Log(object message) {
#if DEBUG
            Console.WriteLine(message);
#endif
        }

        /// <summary>
        /// Prints a formatted message when in debug mode
        /// </summary>
        /// <param name="format">A composite format string</param>
        /// <param name="args">An array of objects to write using format</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe void Log(string format, params object[] args) {
#if DEBUG
            Console.WriteLine(format, args);
#endif
        }

        /// <summary>
        /// Computes the square of a number
        /// </summary>
        /// <param name="x">The value</param>
        /// <returns>x * x</returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static double Square(double x) {
            return x * x;
        }

        /// <summary>
        /// Wipes a region of memory
        /// </summary>
        /// <param name="buffer">The buffer</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe void ClearBuffer(ref byte[] buffer) {
            ClearBuffer(ref buffer, 0, buffer.Length);
        }

        /// <summary>
        /// Wipes a region of memory
        /// </summary>
        /// <param name="buffer">The buffer</param>
        /// <param name="offset">Start index</param>
        /// <param name="length">Number of bytes to clear</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe void ClearBuffer(ref byte[] buffer, int offset, int length) {
            fixed(byte* ptrBuffer = &buffer[offset]) {
                for(int i = 0; i < length; ++i) {
                    *(ptrBuffer + i) = 0;
                }
            }
        }

This works perfectly as a macro, but comes with a little drawback: Methods marked as inlined will be copied to the reflection part of your assembly like any other "normal" method.

2
3

Luckily, C# has no C/C++-style preprocessor - only conditional compilation and pragmas (and possibly something else I cannot recall) are supported. Unfortunatelly, C# has no metaprogramming capabilities (this may actually relate to your question to some extent).

6
  • 9
    I would say it's not the job of the programming language to enforce good style. C# has goto's and a developer has the intelligence not to use them. The same applies for macros, but sometimes I would really like to have them!
    – bytecode77
    Jun 30, 2016 at 10:17
  • Example: "Dispatcher.Invoke(delegate" would be nice to have as a macro in your WPF code.
    – bytecode77
    Aug 3, 2016 at 7:54
  • @bytecode77 Gotos are useful in C#, C and C++ to jump out of nested loops. An approach like Java's continue/break to label is more intelligent but gotos are fine for that. However, macros are not useful in a language where multiplatform support is handled by the language.
    – Winter
    Jul 10, 2017 at 12:46
  • 1
    Even though I encourage both pro's and cons for anything - I don't see how goto'ing out of a loop is superior over a boolean quit variable. Once nested statements come into place, code gets hard to read and maintain. PHP has the break 2..n; statement, C# doesn't. However, C# has enough LINQ extensions to actually not use nested loops in many cases, making the code readable in a different way - which I honestly prefer.
    – bytecode77
    Jul 10, 2017 at 13:08
  • We got here discussing how to deal with hand-written profiling of a hot loop. Luckily is a really bad choice of word.
    – Joshua
    Jul 16, 2018 at 19:33
1

Turn the C Macro into a C# static method in a class.

1
  • 8
    This doesn’t get you CPP macro stringification support. Macros are useful because they treat the code more like plain text than code. However, the OP doesn’t seem to actually want/need macros. For his purposes, this would be a perfectly valid (and better) solution.
    – binki
    Feb 11, 2014 at 22:14
1

I would suggest you to write extension, something like below.

public static class WriteToConsoleExtension
{
   // Extension to all types
   public static void WriteToConsole(this object instance, 
                                     string format, 
                                     params object[] data)
   {
       Console.WriteLine(format, data);
   }
}

class Program
{
    static void Main(string[] args)
    {
        Program p = new Program();
        // Usage of extension
        p.WriteToConsole("Test {0}, {1}", DateTime.Now, 1);
    }
}

Hope this helps (and not too late :) )

3
  • 5
    for me this is just confusing
    – LuckyLikey
    Dec 14, 2015 at 10:56
  • 3
    Extensionitis, as I sometimes call it. Building an API DLL for me often lead to more and more extensions rather than methods. E.g. ValidateUrl(this string) - Something which by now I prefer in a class, as this both tends to bloat intellisense (especially with this object) and makes finding such methods obscure sometimes. Having Validate.Url(string) doesn't blow up the code and is evidently easy for others to find and utilize.
    – bytecode77
    Jul 10, 2017 at 13:13
  • I do agree with you Jul 11, 2017 at 13:49
-1

Use lambdas

void print(string x) => Trace.WriteLine(x);
void println(string x) => Console.WriteLine(x);
void start(string x) => Process.Start(x);

void done() => Trace.WriteLine("Done");
void hey() => Console.WriteLine("hey");
1
  • 1
    This is fundamentally NOT the same as a C/C++ macro. In C/C++, a macro is a replacement. When the C/C++ preprocessor detects the macro, the preprocessor replaces that macro with your code. Therefore, you can have things like returns, continue, etc. Oct 6, 2023 at 6:06