Main() e argomenti della riga di comando

Il metodo Main è il punto di ingresso di un'applicazione C#. Le librerie e i servizi non richiedono un metodo Main come punto di ingresso. All'avvio dell'applicazione, Main è il primo metodo richiamato.

In un programma C# può essere presente un solo punto di ingresso. Se si dispone di più classi con un metodo Main, è necessario compilare il programma con l'opzione del compilatore StartupObject per specificare quale metodo Main usare come punto di ingresso. Per altre informazioni, vedere StartupObject (opzioni del compilatore C#).

class TestClass
{
    static void Main(string[] args)
    {
        // Display the number of command line arguments.
        Console.WriteLine(args.Length);
    }
}

È anche possibile usare istruzioni di primo livello in un file come punto di ingresso per l'applicazione. Proprio come il Main metodo, le istruzioni di primo livello possono anche restituire valori e accedere agli argomenti della riga di comando. Per altre informazioni, vedere Istruzioni di primo livello.

using System.Text;

StringBuilder builder = new();
builder.AppendLine("The following arguments are passed:");

// Display the command line arguments using the args variable.
foreach (var arg in args)
{
    builder.AppendLine($"Argument={arg}");
}

Console.WriteLine(builder.ToString());

// Return a success code.
return 0;

Panoramica

  • Il metodo Main è il punto di ingresso di un programma eseguibile, ovvero il punto in cui il controllo del programma inizia e termina.
  • Main viene dichiarato in una classe o in un tipo struct. Main deve essere static e non deve essere public. Nell'esempio precedente riceve l'accesso predefinito di private. Un contenitore class può essere static.
  • Main può avere un tipo restituito void, int, Task o Task<int>.
  • Se e solo se Main restituisce Task o Task<int>, la dichiarazione di Main può includere il modificatore async. Ciò esclude in modo specifico un metodo async void Main.
  • Il metodo Main può essere dichiarato con o senza un parametro string[] contenente argomenti della riga di comando. Quando si usa Visual Studio per creare applicazioni Windows, è possibile aggiungere il parametro manualmente oppure usare il metodo GetCommandLineArgs() per ottenere gli argomenti della riga di comando. I parametri vengono letti come argomenti della riga di comando a indice zero. A differenza di C e C++, il nome del programma non viene considerato come il primo argomento della riga di comando nella matrice args, ma è il primo elemento del metodo GetCommandLineArgs().

L'elenco seguente mostra le firme Main valide:

public static void Main() { }
public static int Main() { }
public static void Main(string[] args) { }
public static int Main(string[] args) { }
public static async Task Main() { }
public static async Task<int> Main() { }
public static async Task Main(string[] args) { }
public static async Task<int> Main(string[] args) { }

Tutti gli esempi precedenti usano il modificatore della funzione di accesso public. È tipico, ma non obbligatorio.

L'aggiunta dei tipi restituiti async, Task e Task<int> semplifica il codice del programma quando è necessario avviare le applicazioni console e per operazioni asincrone await in Main.

Valori restituiti da Main()

È possibile restituire un int dal metodo Main definendo il metodo in uno dei modi seguenti:

codice del metodoMain firmaMain
Nessun uso di args o await static int Main()
Usa args, senza uso di await static int Main(string[] args)
Nessun uso di args, usa await static async Task<int> Main()
Usa args e await static async Task<int> Main(string[] args)

Se il valore restituito da Main non viene usato, la restituzione di void o Task consente codice leggermente più semplice.

codice del metodoMain firmaMain
Nessun uso di args o await static void Main()
Usa args, senza uso di await static void Main(string[] args)
Nessun uso di args, usa await static async Task Main()
Usa args e await static async Task Main(string[] args)

Tuttavia, la restituzione di int o Task<int> consente al programma di comunicare informazioni sullo stato ad altri programmi o script che richiamano il file eseguibile.

Nell'esempio seguente viene illustrato come è possibile accedere al codice di uscita per il processo.

Questo esempio usa strumenti da riga di comando di .NET Core. Se non si ha familiarità con gli strumenti da riga di comando di .NET Core, è possibile ottenere informazioni su di essi in questo articolo introduttivo.

Creare una nuova applicazione eseguendo dotnet new console. Convertire il metodo Main in program.cs come indicato di seguito:

// Save this program as MainReturnValTest.cs.
class MainReturnValTest
{
    static int Main()
    {
        //...
        return 0;
    }
}

Quando si esegue un programma in ambiente Windows, qualsiasi valore restituito dalla funzione Main viene archiviato in una variabile di ambiente. Questa variabile di ambiente può essere recuperata mediante ERRORLEVEL da un file batch o mediante $LastExitCode da PowerShell.

È possibile compilare l'applicazione usando il comando dotnet CLIdotnet build.

Quindi creare uno script di PowerShell per eseguire l'applicazione e visualizzare il risultato. Incollare il codice seguente in un file di testo e salvarlo come test.ps1 nella cartella che contiene il progetto. Eseguire lo script di PowerShell digitando test.ps1 al prompt di PowerShell.

Poiché il codice restituisce zero, il file batch indicherà un esito positivo. Tuttavia, se si modifica MainReturnValTest.cs per restituire un valore diverso da zero e poi ricompilare il programma, l'esecuzione successiva dello script di PowerShell segnala un errore.

dotnet run
if ($LastExitCode -eq 0) {
    Write-Host "Execution succeeded"
} else
{
    Write-Host "Execution Failed"
}
Write-Host "Return value = " $LastExitCode
Execution succeeded
Return value = 0

Valori restituiti da Async Main

Quando si dichiara un valore restituito async per Main, il compilatore genera il codice boilerplate per chiamare metodi asincroni in Main. Se non si specifica la parola chiave async, è necessario scrivere manualmente il codice, come illustrato nell'esempio seguente. Il codice nell'esempio garantisce che il programma venga eseguito fino al completamento dell'operazione asincrona:

class AsyncMainReturnValTest
{
    public static void Main()
    {
        AsyncConsoleWork().GetAwaiter().GetResult();
    }

    private static async Task<int> AsyncConsoleWork()
    {
        // Main body here
        return 0;
    }
}

Questo codice boilerplate può essere sostituito da:

class Program
{
    static async Task<int> Main(string[] args)
    {
        return await AsyncConsoleWork();
    }

    private static async Task<int> AsyncConsoleWork()
    {
        // main body here 
        return 0;
    }
}

Un vantaggio della dichiarazione di Main come async è che il compilatore genera sempre il codice corretto.

Quando il punto di ingresso dell'applicazione restituisce Task o Task<int> il compilatore genera un nuovo punto di ingresso che chiama il metodo del punto di ingresso dichiarato nel codice dell'applicazione. Supponendo che questo punto di ingresso sia denominato $GeneratedMain, il compilatore genera il codice seguente per questi punti di ingresso:

  • static Task Main(): il compilatore produce l'equivalente di private static void $GeneratedMain() => Main().GetAwaiter().GetResult();
  • static Task Main(string[]): il compilatore produce l'equivalente di private static void $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();
  • static Task<int> Main(): il compilatore produce l'equivalente di private static int $GeneratedMain() => Main().GetAwaiter().GetResult();
  • static Task<int> Main(string[]): il compilatore produce l'equivalente di private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();

Nota

Se negli esempi si fosse usato il modificatore async sul metodo Main il compilatore avrebbe generato lo stesso codice.

Argomenti della riga di comando

È possibile inviare argomenti al metodo Main definendo il metodo in uno dei modi seguenti:

codice del metodoMain firmaMain
Nessun valore restituito, nessun uso di await static void Main(string[] args)
Valore restituito, nessun uso di await static int Main(string[] args)
Nessun valore restituito, usa await static async Task Main(string[] args)
Valore restituito, usa await static async Task<int> Main(string[] args)

Se gli argomenti non vengono usati, è possibile omettere args dalla firma del metodo per codice leggermente più semplice:

codice del metodoMain firmaMain
Nessun valore restituito, nessun uso di await static void Main()
Valore restituito, nessun uso di await static int Main()
Nessun valore restituito, usa await static async Task Main()
Valore restituito, usa await static async Task<int> Main()

Nota

È anche possibile usare Environment.CommandLine o Environment.GetCommandLineArgs per accedere agli argomenti della riga di comando da qualsiasi punto in una console o Windows Forms Application. Per abilitare gli argomenti della riga di comando nella firma del metodo Main in un'applicazione Windows Form, è necessario modificare manualmente la firma di Main. Il codice generato dalla finestra di progettazione di Windows Form crea Main senza un parametro di input.

Il parametro del metodo Main è una matrice String che rappresenta gli argomenti della riga di comando. In genere si determina se gli argomenti esistono eseguendo il test della proprietà Length, ad esempio:

if (args.Length == 0)
{
    System.Console.WriteLine("Please enter a numeric argument.");
    return 1;
}

Suggerimento

La matrice args non può essere Null. Quindi, è sicuro accedere alla proprietà Length senza il controllo Null.

È anche possibile convertire gli argomenti stringa in tipi numerici con la classe Convert o il metodo Parse. Ad esempio, l'istruzione seguente converte string in un numero long con il metodo Parse:

long num = Int64.Parse(args[0]);

È anche possibile usare il tipo C# long, che fa da alias per Int64:

long num = long.Parse(args[0]);

Nella classe Convert il metodo ToInt64 consente di eseguire la stessa operazione:

long num = Convert.ToInt64(s);

Per altre informazioni, vedere Parse e Convert.

Suggerimento

L'analisi degli argomenti della riga di comando può essere complessa. Prendere in considerazione l'uso della libreria System.CommandLine (attualmente in versione beta) per semplificare il processo.

L'esempio seguente illustra come usare gli argomenti della riga di comando in un'applicazione console. L'applicazione accetta un argomento in fase di esecuzione, lo converte in un numero intero e calcola il fattoriale del numero. Se non viene specificato nessun argomento, l'applicazione produce un messaggio che descrive l'uso corretto del programma.

Per compilare ed eseguire l'applicazione al prompt dei comandi, seguire questa procedura:

  1. Incollare il codice seguente in qualsiasi editor di testo e quindi salvare il file come file di testo con il nome Factorial.cs.

    public class Functions
    {
        public static long Factorial(int n)
        {
            // Test for invalid input.
            if ((n < 0) || (n > 20))
            {
                return -1;
            }
    
            // Calculate the factorial iteratively rather than recursively.
            long tempResult = 1;
            for (int i = 1; i <= n; i++)
            {
                tempResult *= i;
            }
            return tempResult;
        }
    }
    
    class MainClass
    {
        static int Main(string[] args)
        {
            // Test if input arguments were supplied.
            if (args.Length == 0)
            {
                Console.WriteLine("Please enter a numeric argument.");
                Console.WriteLine("Usage: Factorial <num>");
                return 1;
            }
    
            // Try to convert the input arguments to numbers. This will throw
            // an exception if the argument is not a number.
            // num = int.Parse(args[0]);
            int num;
            bool test = int.TryParse(args[0], out num);
            if (!test)
            {
                Console.WriteLine("Please enter a numeric argument.");
                Console.WriteLine("Usage: Factorial <num>");
                return 1;
            }
    
            // Calculate factorial.
            long result = Functions.Factorial(num);
    
            // Print result.
            if (result == -1)
                Console.WriteLine("Input must be >= 0 and <= 20.");
            else
                Console.WriteLine($"The Factorial of {num} is {result}.");
    
            return 0;
        }
    }
    // If 3 is entered on command line, the
    // output reads: The factorial of 3 is 6.
    
  2. Nella schermata Start o menu Start, aprire una finestra del prompt dei comandi per gli sviluppatori di Visual Studio e quindi passare alla cartella contenente il file creato.

  3. Immettere il seguente comando per compilare l'applicazione.

    dotnet build

    Se l'applicazione non presenta errori di compilazione, viene creato un file eseguibile denominato Factorial.exe.

  4. Immettere il comando seguente per calcolare il fattoriale di 3:

    dotnet run -- 3

  5. Il comando produce il seguente output: The factorial of 3 is 6.

Nota

Quando si esegue un'applicazione in Visual Studio, è possibile specificare argomenti della riga di comando nella Pagina Debug, Progettazione progetti.

Specifiche del linguaggio C#

Per altre informazioni, vedere la specifica del linguaggio C#. La specifica del linguaggio costituisce il riferimento ufficiale principale per la sintassi e l'uso di C#.

Vedi anche