Condividi tramite


Main() e argomenti della riga di comando

Il metodo Main è il punto di ingresso di un'applicazione C#. 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. Analogamente al metodo Main, anche le istruzioni di primo livello possono 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 deve essere dichiarato in una classe o uno struct. L'elemento class contenitore può essere static.
  • Il parametro Main deve essere impostato su static.
  • Main può includere qualsiasi modificatore di accesso (eccetto file).
  • 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 dichiarazioni di Main più comuni:

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

Gli esempi precedenti non specificano un modificatore di accesso, quindi sono private in modo implicito per impostazione predefinita. Si tratta di un comportamento standard, ma è possibile specificare qualsiasi modificatore di accesso esplicito.

Suggerimento

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:

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

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

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

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 build dell'interfaccia della riga di comando di dotnet.

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 int Main()
    {
        return 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:

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

Se non si usano gli argomenti, è possibile omettere args dalla dichiarazione del metodo per semplificare leggermente il codice:

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

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 dichiarazione del metodo Main in una Windows Forms Application, è necessario modificare manualmente la dichiarazione 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. Per semplificare il processo, provare a usare la libreria System.CommandLine, attualmente disponibile in versione beta.

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