Main() e argumentos de linha de comando

O método Main é o ponto de entrada de um aplicativo C#. (Bibliotecas e serviços não exigem um método Main como ponto de entrada). Quando o aplicativo é iniciado, o método Main é o primeiro método invocado.

Pode haver apenas um ponto de entrada em um programa C#. Se tiver mais de uma classe que tenha um método Main, você deverá compilar seu programa com a opção do compilador StartupObject para especificar qual método Main será usado como ponto de entrada. Para obter mais informações, consulte StartupObject (opções de compilador do C#).

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

Você também pode usar Instruções de nível superior em um arquivo como o ponto de entrada no seu aplicativo. Assim como o método Main, as instruções de nível superior também podem retornar valores e acessar argumentos de linha de comando. Para obter mais informações, consulte Instruções de nível superior.

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;

Visão geral

  • O método Main é o ponto de entrada de um programa executável; é onde o controle do programa começa e termina.
  • Main é declarado dentro de uma classe ou struct. Main deve ser static e não precisa ser public. (No exemplo anterior, ele recebe o acesso padrão de private.) Uma delimitação class pode ser static.
  • Main pode ter o tipo de retorno void, int, Task ou Task<int>.
  • Se e somente se Main retornar um Task ou Task<int>, a declaração de Main pode incluir o modificador async. Isso exclui especificamente um método async void Main.
  • O método Main pode ser declarado com ou sem um parâmetro string[] que contém os argumentos de linha de comando. Ao usar o Visual Studio para criar aplicativos do Windows, você pode adicionar o parâmetro manualmente ou usar o método GetCommandLineArgs() para obter os argumentos de linha de comando. Os parâmetros são lidos como argumentos de linha de comando indexados por zero. Ao contrário do C e C++, o nome do programa não é tratado como o primeiro argumento de linha de comando na matriz args, mas é o primeiro elemento do método GetCommandLineArgs().

A lista a seguir mostra as assinaturas de Main válidas:

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

Todos os exemplos anteriores usam o modificador do acessador public. Isso é típico, mas não é necessário.

A adição dos tipos de retorno async, Task e Task<int> simplifica o código do programa quando os aplicativos do console precisam iniciar e realizar operações assíncronas await no Main.

Valores de retorno de Main()

Você pode retornar um int do método Main ao definir o método de uma das seguintes maneiras:

Código do método Main Assinatura Main
Nenhum uso de args ou await static int Main()
Usa args, nenhum uso de await static int Main(string[] args)
Nenhum uso de args, usa await static async Task<int> Main()
Usa args e await static async Task<int> Main(string[] args)

Se o valor retornado de Main não for usado, o retorno de void ou Task permite um código um pouco mais simples.

Código do método Main Assinatura Main
Nenhum uso de args ou await static void Main()
Usa args, nenhum uso de await static void Main(string[] args)
Nenhum uso de args, usa await static async Task Main()
Usa args e await static async Task Main(string[] args)

No entanto, o retorno de int ou Task<int> habilita o programa a comunicar informações de status para outros programas ou scripts, que invocam o arquivo executável.

O exemplo a seguir mostra como o código de saída para o processo pode ser acessado.

Este exemplo usa ferramentas de linha de comando do .NET Core. Se você não estiver familiarizado com as ferramentas de linha de comando do .NET Core, poderá aprender sobre elas neste artigo de introdução.

Crie um novo aplicativo ao executar dotnet new console. Modifique o método Main em Program.cs da seguinte maneira:

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

Quando um programa é executado no Windows, qualquer valor retornado da função Main é armazenado em uma variável de ambiente. Essa variável de ambiente pode ser recuperada usando ERRORLEVEL de um arquivo em lotes ou $LastExitCode do PowerShell.

Você pode criar o aplicativo usando o comando dotnet build da CLI do dotnet.

Em seguida, crie um script do PowerShell para executar o aplicativo e exibir o resultado. Cole o código a seguir em um arquivo de texto e salve-o como test.ps1 na pasta que contém o projeto. Execute o script do PowerShell ao digitar test.ps1 no prompt do PowerShell.

Como o código retorna zero, o arquivo em lotes relatará êxito. No entanto, se você alterar o MainReturnValTest.cs para retornar um valor diferente de zero e recompilar o programa, a execução subsequente do script do PowerShell reportará falha.

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

Valores retornados de Async Main

Quando você declara um valor retornado async para Main, o compilador gera o código clichê para chamar métodos assíncronos em Main. Se você não especificar a palavra-chave async, precisará escrever esse código por conta própria, conforme mostrado no exemplo a seguir. O código no exemplo garante que o programa seja executado até que a operação assíncrona seja concluída:

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

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

Este código clichê pode ser substituído por:

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

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

A vantagem de declarar Main como async é que o compilador sempre gera o código correto.

Quando o ponto de entrada do aplicativo retorna um Task ou Task<int>, o compilador gera um novo ponto de entrada que chama o método de ponto de entrada declarado no código do aplicativo. Supondo que esse ponto de entrada é chamado $GeneratedMain, o compilador gera o código a seguir para esses pontos de entrada:

  • static Task Main() resulta no compilador emitindo o equivalente a private static void $GeneratedMain() => Main().GetAwaiter().GetResult();
  • static Task Main(string[]) resulta no compilador emitindo o equivalente a private static void $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();
  • static Task<int> Main() resulta no compilador emitindo o equivalente a private static int $GeneratedMain() => Main().GetAwaiter().GetResult();
  • static Task<int> Main(string[]) resulta no compilador emitindo o equivalente a private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();

Observação

Se os exemplos usassem o modificador async no método Main, o compilador geraria o mesmo código.

Argumentos de linha de comando

Você pode enviar argumentos para o método Main definindo o método de uma das seguintes maneiras:

Código do método Main Assinatura Main
Nenhum valor retornado, nenhum uso de await static void Main(string[] args)
Valor retornado, nenhum uso de await static int Main(string[] args)
Nenhum valor retornado, usa await static async Task Main(string[] args)
Valor retornado, usa await static async Task<int> Main(string[] args)

Se os argumentos não forem usados, você poderá omitir args a assinatura do método para um código ligeiramente mais simples:

Código do método Main Assinatura Main
Nenhum valor retornado, nenhum uso de await static void Main()
Valor retornado, nenhum uso de await static int Main()
Nenhum valor retornado, usa await static async Task Main()
Valor retornado, usa await static async Task<int> Main()

Observação

Você também pode usar Environment.CommandLine ou Environment.GetCommandLineArgs para acessar os argumentos de linha de comando de qualquer ponto em um console ou um aplicativo do Windows Forms. Para habilitar os argumentos de linha de comando na assinatura do método Main em um aplicativo do Windows Forms, você deve modificar manualmente a assinatura de Main. O código gerado pelo designer do Windows Forms cria um Main sem um parâmetro de entrada.

O parâmetro do método Main é uma matriz String que representa os argumentos de linha de comando. Geralmente você determina se os argumentos existem testando a propriedade Length, por exemplo:

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

Dica

A matriz args não pode ser nula. Portanto, é seguro acessar a propriedade Length sem verificação de nulos.

Você também pode converter os argumentos de cadeia de caracteres em tipos numéricos, usando a classe Convert ou o método Parse. Por exemplo, a instrução a seguir converte o string em um número long usando o método Parse:

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

Também é possível usar o tipo long de C#, que funciona como alias de Int64:

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

Você também pode usar o método da classe Convert, o ToInt64, para fazer a mesma coisa:

long num = Convert.ToInt64(s);

Para obter mais informações, consulte Parse e Convert.

Dica

A análise de argumentos de linha de comando pode ser complexa. Considere usar a biblioteca System.CommandLine (atualmente em beta) para simplificar o processo.

O exemplo a seguir mostra como usar argumentos de linha de comando em um aplicativo de console. O aplicativo recebe um argumento em tempo de execução, converte o argumento em um número inteiro e calcula o fatorial do número. Se nenhum argumento for fornecido, o aplicativo emitirá uma mensagem que explica o uso correto do programa.

Para compilar e executar o aplicativo em um prompt de comando, siga estas etapas:

  1. Cole o código a seguir em qualquer editor de texto e, em seguida, salve o arquivo como um arquivo de texto com o 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. Na tela Inicial ou no menu Iniciar, abra uma janela Prompt de Comando do Desenvolvedor do Visual Studio e, em seguida, navegue até a pasta que contém o arquivo que você acabou de criar.

  3. Digite o seguinte comando para compilar o aplicativo.

    dotnet build

    Se seu aplicativo não tiver erros de compilação, um arquivo executável chamado Factorial.exe será criado.

  4. Digite o seguinte comando para calcular o fatorial de 3:

    dotnet run -- 3

  5. O comando produz esta saída: The factorial of 3 is 6.

Observação

Ao executar um aplicativo no Visual Studio, você pode especificar argumentos de linha de comando na Página de depuração, Designer de Projeto.

Especificação da linguagem C#

Para obter mais informações, consulte a Especificação da linguagem C#. A especificação da linguagem é a fonte definitiva para a sintaxe e o uso de C#.

Confira também