Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Macro definitions in Preprocessor

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.


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.


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.


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;
    }
  }
}

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.


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).


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