Direttive per il preprocessore

Suggerimento

Novità dello sviluppo di software? Non sono necessarie direttive del preprocessore immediatamente. Concentrarsi prima sui tutorial Get started e tornare qui quando i progetti richiedono la compilazione condizionale o la configurazione di build.

Esperienza in un'altra lingua? Se si ha familiarità con #ifdef in C/C++ o nella compilazione condizionale in altri linguaggi, le direttive del preprocessore C# funzionano in modo analogo. Passare alla sintassi necessaria.

Le direttive del preprocessore C# indicano al compilatore quale codice includere, escludere o trattare in modo diverso quando compila l'app. Queste indicazioni possono modificare il programma risultante. Le direttive del preprocessore iniziano sempre con # e devono essere visualizzate nella propria riga (ignorando gli spazi vuoti iniziali). È possibile aggiungere un commento finale dopo la direttiva . Mentre il linguaggio di riferimento documenta tutte le direttive disponibili, tre gruppi riguardano l'uso quotidiano:

  • App basate su file (#:): configurare le app basate su file.
  • Compilazione condizionale (#if / #elif / #else / #endif): includere o escludere il codice in base alla configurazione di compilazione o al framework di destinazione.
  • Eliminazione degli avvisi (#pragma warning): eliminare o ripristinare avvisi specifici del compilatore.

Direttive applicazione basate su file

A partire da C# 14, le app basate su file usano due direttive aggiuntive:

  • #! — la riga shebang che consente di eseguire il file direttamente in Unix (ad esempio, ./Program.cs). Questa operazione richiede l'autorizzazione di esecuzione da impostare nel file (chmod +x <file>).
  • #: — direttive del sistema di compilazione che configurano pacchetti, impostazioni SDK e altre opzioni per programmi a file singolo.

Usare #:package per aggiungere un pacchetto NuGet. Ad esempio, la seguente app basata su file utilizza il pacchetto Spectre.Console per effettuare il rendering dell'output con stile.

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

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

È possibile specificare una versione esatta con @o usare @* per eseguire il pull della versione più recente. Aggiungere direttive #:package multiple per includere altri pacchetti:

#:package Serilog@3.1.1

Altre #: direttive consentono di fare riferimento a progetti, impostare le proprietà di MSBuild o modificare l'SDK:

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

Per l'elenco completo delle direttive, vedere App basate su file e informazioni di riferimento sul linguaggio.

Compilazione condizionale

Usare #if, #elif#else, e #endif per includere o escludere il codice in base alla definizione di un simbolo. I simboli più comuni sono DEBUG (impostati automaticamente per le compilazioni di debug) e i simboli del framework di destinazione, ad esempio 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
}

Il sistema di compilazione definisce il DEBUG simbolo quando si compila nella configurazione di debug. Non è necessario definirlo manualmente. I simboli del framework di destinazione, ad NET10_0_OR_GREATER esempio e NET8_0_OR_GREATER consentono di scrivere codice che si adatta a diverse versioni di .NET nei progetti con più destinazioni.

È possibile combinare i simboli con operatori logici: && (e), || (o) e ! (non):

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
}

Usare #define nella parte superiore di un file per definire i propri simboli. È anche possibile definire simboli per l'intero progetto usando la DefineConstants proprietà nel file di progetto.

Eliminazione degli avvisi

Usare #pragma warning disable per eliminare avvisi specifici del compilatore e #pragma warning restore riabilitarli. Definire sempre l'ambito dell'eliminazione nel modo più stretto possibile:

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

Suggerimento

Specificare sempre il numero di avviso, ad esempio CS0168, anziché disabilitare tutti gli avvisi. Questo approccio mantiene l'eliminazione mirata e rende chiaro il motivo per cui viene eliminato un avviso.