webentwicklung-frage-antwort-db.com.de

C # Makrodefinitionen in Preprozessor

Kann C # Makros definieren, wie dies in der Programmiersprache C mit Präprozessoranweisungen erfolgt? Ich möchte das regelmäßige Tippen bestimmter wiederholter Anweisungen wie die folgenden vereinfachen: 

Console.WriteLine("foo");
55
cl123

Nein, C # unterstützt keine Präprozessor-Makros wie C. Visual Studio hingegen hat snippets . Die Ausschnitte aus Visual Studio sind eine Funktion von IDE und werden im Editor erweitert, anstatt im Code beim Kompilieren durch einen Präprozessor ersetzt zu werden.

43
Andrew Hare

Sie können einen C-Präprozessor (wie mcpp) verwenden und in Ihre .csproj-Datei einfügen. Dann können Sie die "Build-Aktion" für Ihre Quelldatei von Compile bis Preprocess oder wie auch immer Sie es nennen . Fügen Sie einfach BeforBuild zu Ihrem .csproj hinzu:

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

Möglicherweise müssen Sie Compile für mindestens eine Datei (in einem Texteditor) in Preprocess ändern. In diesem Fall sollte die Option "Preprocess" in Visual Studio zur Auswahl stehen.

Ich weiß, dass Makros stark überlastet und missbraucht werden, aber das vollständige Entfernen ist genauso schlecht, wenn nicht sogar schlimmer. Ein klassisches Beispiel für die Verwendung von Makros wäre NotifyPropertyChanged . Jeder Programmierer, der diesen Code tausende Male von Hand neu schreiben musste, weiß, wie schmerzhaft es ohne Makros ist.

31
user2224389

Ich verwende dies, um Console.WriteLine(...) zu vermeiden:

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

und dann können Sie Folgendes verwenden:

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

es ist knapp und irgendwie funky.

26
anthonybell

Sie können zwar keine Makros schreiben, aber bei der Vereinfachung von Beispielen wie Ihrem Beispiel bietet C # 6.0 jetzt statische Verwendungen. Hier ist das Beispiel, das Martin Pernica zu seinem Medium-Artikel gab:

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

Es gibt kein direktes Äquivalent zu C-Stil-Makros in C #, aber inlined statische Methoden - mit oder ohne #if/#elseif/#else pragmas - sind die nächsten, die Sie erhalten können

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

Dies funktioniert perfekt als Makro, hat jedoch einen kleinen Nachteil: Methoden, die als inlined markiert sind, werden wie jede andere "normale" Methode in den Reflection-Teil Ihrer Assembly kopiert.

4

Glücklicherweise hat C # keinen Präprozessor im C/C++ - Stil - nur bedingte Kompilierung und Pragmas (und möglicherweise etwas anderes, an das ich mich nicht erinnern kann) werden unterstützt. Leider verfügt C # nicht über Metaprogrammierungsfunktionen (dieses möglicherweise kann sich in gewissem Maße auf Ihre Frage beziehen).

2
Anton Gogolev

Verwandeln Sie das C-Makro in eine statische C # -Methode in einer Klasse.

2
Robert

Da C # 7.0 using static-Direktive und Local-Funktionen unterstützt, benötigen Sie in den meisten Fällen keine Präprozessor-Makros. 

0
moien

Ich würde vorschlagen, dass Sie eine Erweiterung schreiben, etwa unten.

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

Hoffe das hilft (und nicht zu spät :)) 

0
Milan Jaric