Präprozessordirektiven

Tipp

Neu bei der Entwicklung von Software? Sie benötigen keine Präprozessordirektiven sofort. Konzentrieren Sie sich zuerst auf die Lernprogramme " Erste Schritte ", und kehren Sie hierher zurück, wenn Ihre Projekte eine bedingte Kompilierung oder Buildkonfiguration erfordern.

Haben Sie Erfahrung in einer anderen Sprache? Wenn Sie mit C/C++ oder der bedingten Kompilierung in anderen Sprachen vertraut #ifdef sind, funktionieren C#-Präprozessordirektiven ähnlich. Überspringen Sie zum benötigten Abschnitt mit der Syntax.

C#-Präprozessordirektiven weisen den Compiler an, welcher Code bei der Erstellung Ihrer App eingeschlossen, ausgeschlossen oder anders behandelt werden soll. Diese Anleitung kann das resultierende Programm ändern. Präprozessordirektiven beginnen immer mit # und müssen in ihrer eigenen Zeile angezeigt werden (führende Leerzeichen ignorieren). Sie können einen Kommentar am Ende der Anweisung hinzufügen. Während die Sprachreferenz alle verfügbaren Direktiven dokumentiert, decken drei Gruppen den täglichen Gebrauch ab:

  • Dateibasierte Apps (#:) – konfigurieren Sie dateibasierte Apps.
  • Bedingte Kompilierung (#if / #elif / #else / #endif) – Einschließen oder Ausschließen von Code basierend auf buildkonfiguration oder Zielframework.
  • Warnungsunterdrückung (#pragma warning) – Unterdrücken oder Wiederherstellen bestimmter Compilerwarnungen.

Dateibasierte App-Direktiven

Ab C# 14 verwenden dateibasierte Apps zwei zusätzliche Direktiven:

  • #! — die Shebang-Linie , die die Ausführung der Datei direkt auf Unix ermöglicht (z. B ./Program.cs. ). Dazu muss die Ausführungsberechtigung für die Datei (chmod +x <file>) festgelegt werden.
  • #: – Buildsystemdirektiven, die Pakete, SDK-Einstellungen und andere Optionen für Einzeldateiprogramme konfigurieren.

Verwenden Sie #:package, um ein NuGet-Paket hinzuzufügen. Die folgende dateibasierte App verwendet z. B. das Spectre.Console Paket zum Rendern der formatierten Ausgabe:

#!/usr/bin/env dotnet
#:package Spectre.Console@*

AnsiConsole.MarkupLine("[bold green]Hello[/] from a file-based app!");

Sie können eine genaue Version mit @ festlegen oder @* verwenden, um die neueste Version abzurufen. Fügen Sie mehrere #:package Direktiven hinzu, um weitere Pakete einzuschließen:

#:package Serilog@3.1.1

Mit anderen #: Direktiven können Sie auf Projekte verweisen, MSBuild-Eigenschaften festlegen oder das SDK ändern:

#:project ../SharedLibrary/SharedLibrary.csproj
#:property PublishAot=false
#:sdk Microsoft.NET.Sdk.Web

Eine vollständige Liste der Direktiven finden Sie unter dateibasierte Apps und die Sprachreferenz.

Bedingte Kompilierung

Verwenden Sie #if, #elif, #else und #endif , um Code einzuschließen oder auszuschließen, je nachdem, ob ein Symbol definiert ist. Die am häufigsten verwendeten Symbole sind DEBUG (automatisch für Debugbuilds festgelegt) und Zielframeworksymbole wie NET10_0_OR_GREATER:

static void ConfigureLogging()
{
#if DEBUG
    Console.WriteLine("Debug logging enabled — verbose output active.");
#else
    Console.WriteLine("Release logging — errors only.");
#endif
}

Das Buildsystem definiert das DEBUG Symbol beim Erstellen in der Debugkonfiguration. Sie müssen sie nicht selbst definieren. Zielframeworksymbole wie NET10_0_OR_GREATER und NET8_0_OR_GREATER ermöglichen Ihnen das Schreiben von Code, der sich an verschiedene .NET-Versionen in Multi-Targeting-Projekten anpasst.

Sie können Symbole mit logischen Operatoren kombinieren: && (und), || (oder) und ! (nicht):

static void ShowPlatformInfo()
{
#if NET10_0_OR_GREATER
    Console.WriteLine("Running on .NET 10 or later.");
#elif NET8_0_OR_GREATER
    Console.WriteLine("Running on .NET 8 or 9.");
#else
    Console.WriteLine("Running on an older .NET version.");
#endif
}

Verwenden Sie #define oben in einer Datei, um Ihre eigenen Symbole zu definieren. Sie können auch Symbole für das gesamte Projekt definieren, indem Sie die DefineConstants Eigenschaft in der Projektdatei verwenden.

Warnunterdrückung

#pragma warning disable verwenden, um bestimmte Compilerwarnungen zu unterdrücken, und #pragma warning restore verwenden, um sie wieder zu aktivieren. Beschränken Sie die Unterdrückung immer so eng wie möglich:

    static void ProcessData()
    {
        try
        {
            // Some operation that might fail
            var data = File.ReadAllText("config.json");
            Console.WriteLine($"Config loaded: {data.Length} characters");
        }
#pragma warning disable CS0168 // Variable is declared but never used
        catch (FileNotFoundException ex)
#pragma warning restore CS0168
        {
            // Fall back to defaults — the exception details aren't needed here
            Console.WriteLine("Config file not found, using defaults.");
        }
    }

Tipp

Geben Sie immer die Warnungsnummer an, wie zum Beispiel CS0168, anstatt alle Warnungen zu deaktivieren. Dieser Ansatz hält die Unterdrückung gezielt und macht deutlich, warum eine Warnung unterdrückt wird.