Compartir vía


Main() y argumentos de línea de comandos

El método Main es el punto de entrada de una aplicación de C# Cuando se inicia la aplicación, el método Main es el primero que se invoca.

Solo puede haber un punto de entrada en un programa de C#. Si hay más de una clase que tenga un método Main, deberá compilar el programa con la opción del compilador StartupObject para especificar qué método Main quiere utilizar como punto de entrada. Para obtener más información, consulte StartupObject (opciones del compilador de C#).

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

También puede usar instrucciones de nivel superior en un archivo como punto de entrada para la aplicación. Al igual que el método Main, las instrucciones de nivel superior también pueden devolver valores y acceder a los argumentos de la línea de comandos. Para más información, consulte Instrucciones de nivel 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;

Información general

  • El método Main es el punto de entrada de un programa ejecutable; es donde se inicia y finaliza el control del programa.
  • Main debe declararse dentro de una clase o estructura. La class envolvente puede ser static.
  • Main debe ser static.
  • Main puede tener cualquier modificador de acceso (excepto file).
  • Main puede tener un tipo de valor devuelto void, int, Task o Task<int>.
  • Solo si Main devuelve un tipo de valor devuelto Task o Task<int>, la declaración de Main puede incluir el modificador async, Esto excluye específicamente un método async void Main.
  • El método Main se puede declarar con o sin un parámetro string[] que contiene los argumentos de línea de comandos. Al usar Visual Studio para crear aplicaciones Windows, se puede agregar el parámetro manualmente o usar el método GetCommandLineArgs() con el fin de obtener los argumentos de la línea de comandos. Los parámetros se leen como argumentos de línea de comandos indizados con cero. A diferencia de C y C++, el nombre del programa no se trata como el primer argumento de línea de comandos en la matriz args, pero es el primer elemento del método GetCommandLineArgs().

En la lista siguiente, se muestran las declaraciones Main más comunes:

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

Los ejemplos anteriores no especifican un modificador de acceso, por lo que son implícitamente private de forma predeterminada. Esto es típico, pero es posible especificar cualquier modificador de acceso explícito.

Sugerencia

Al agregar los tipos de valor devuelto async, Task y Task<int>, se simplifica el código de programa cuando las aplicaciones de consola tienen que realizar tareas de inicio y await de operaciones asincrónicas en Main.

Valores devueltos Main()

Puede devolver un objeto int desde el método Main si lo define de una de las siguientes maneras:

declaración Main Código del método Main
static int Main() No se usa args ni await
static int Main(string[] args) Se usa args, no se usa await
static async Task<int> Main() No se usa args, se usa await
static async Task<int> Main(string[] args) Se usan args y await

Si el valor devuelto de Main no se usa, la devolución de void o Task permite que el código sea ligeramente más sencillo.

declaración Main Código del método Main
static void Main() No se usa args ni await
static void Main(string[] args) Se usa args, no se usa await
static async Task Main() No se usa args, se usa await
static async Task Main(string[] args) Se usan args y await

Pero, si se devuelve int o Task<int>, el programa puede comunicar información de estado a otros programas o scripts que invocan el archivo ejecutable.

En el ejemplo siguiente se muestra cómo se puede acceder al código de salida para el proceso.

En este ejemplo se usan las herramientas de línea de comandos de .NET Core. Si no está familiarizado con las herramientas de línea de comandos de .NET Core, puede obtener información sobre ellas en este artículo de introducción.

Cree una aplicación mediante la ejecución de dotnet new console. Modifique el método Main en Program.cs como se indica a continuación:

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

Cuando un programa se ejecuta en Windows, cualquier valor devuelto por la función Main se almacena en una variable de entorno. Esta variable de entorno se puede recuperar mediante ERRORLEVEL desde un archivo por lotes, o mediante $LastExitCode desde PowerShell.

Puede compilar la aplicación mediante el comando dotnet build de la CLI de dotnet.

Después, cree un script de PowerShell para ejecutar la aplicación y mostrar el resultado. Pegue el código siguiente en un archivo de texto y guárdelo como test.ps1 en la carpeta que contiene el proyecto. Ejecute el script de PowerShell. Para ello, escriba test.ps1 en el símbolo del sistema de PowerShell.

Dado que el código devuelve el valor cero, el archivo por lotes comunicará un resultado satisfactorio. En cambio, si cambia MainReturnValTest.cs para que devuelva un valor distinto de cero y luego vuelve a compilar el programa, la ejecución posterior del script de PowerShell informará de que se ha producido un error.

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 devueltos asincrónicos de Main

Cuando se declara un valor devuelto async para Main, el compilador genera el código reutilizable para llamar a métodos asincrónicos en Main. Si no especifica la palabra clave async, debe escribir ese código usted mismo, como se muestra en el siguiente ejemplo. El código del ejemplo garantiza que el programa se ejecute hasta que se complete la operación asincrónica:

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

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

Este código reutilizable se puede reemplazar por:

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

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

Una ventaja de declarar Main como async es que el compilador siempre genera el código correcto.

Cuando el punto de entrada de la aplicación devuelve Task o Task<int>, el compilador genera un nuevo punto de entrada que llama al método de punto de entrada declarado en el código de la aplicación. Suponiendo que este punto de entrada se denomina $GeneratedMain, el compilador genera el código siguiente para estos puntos de entrada:

  • static Task Main() hace que el compilador emita el equivalente de private static void $GeneratedMain() => Main().GetAwaiter().GetResult();
  • static Task Main(string[]) hace que el compilador emita el equivalente de private static void $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();
  • static Task<int> Main() hace que el compilador emita el equivalente de private static int $GeneratedMain() => Main().GetAwaiter().GetResult();
  • static Task<int> Main(string[]) hace que el compilador emita el equivalente de private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();

Nota

Si en los ejemplos se usase el modificador async en el método Main, el compilador generaría el mismo código.

Argumentos de la línea de comandos

Puede enviar argumentos al método Main definiéndolo de una de las siguientes maneras:

declaración Main Código del método Main
static void Main(string[] args) No hay valores devueltos, no se usa await
static int Main(string[] args) Valor devuelto, no se usa await
static async Task Main(string[] args) No hay valores devueltos, se usa await
static async Task<int> Main(string[] args) Valor devuelto, se usa await

Si no se usan los argumentos, puede omitir args de la declaración del método para simplificar ligeramente el código:

declaración Main Código del método Main
static void Main() No hay valores devueltos, no se usa await
static int Main() Valor devuelto, no se usa await
static async Task Main() No hay valores devueltos, se usa await
static async Task<int> Main() Valor devuelto, se usa await

Nota

También puede usar Environment.CommandLine o Environment.GetCommandLineArgs para acceder a los argumentos de la línea de comandos desde cualquier punto de una consola o de una aplicación de Windows Forms. Para habilitar los argumentos de la línea de comandos en la declaración del método Main de una aplicación Windows Forms, tendrá que modificar manualmente la declaración de Main. El código generado por el diseñador de Windows Forms crea un Main sin ningún parámetro de entrada.

El parámetro del método Main es una matriz String que representa los argumentos de la línea de comandos. Normalmente, para determinar si hay argumentos, se prueba la propiedad Length; por ejemplo:

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

Sugerencia

La matriz args no puede ser NULL. así que es seguro acceder a la propiedad Length sin comprobar los valores NULL.

También puede convertir los argumentos de cadena en tipos numéricos mediante la clase Convert o el método Parse. Por ejemplo, la siguiente instrucción convierte la string en un número long mediante el método Parse:

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

También se puede usar el tipo de C# long, que tiene como alias Int64:

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

También puede usar el método ToInt64 de la clase Convert para hacer lo mismo:

long num = Convert.ToInt64(s);

Para obtener más información, vea Parse y Convert.

Sugerencia

El análisis de argumentos de línea de comandos puede ser complejo. Considere la posibilidad de usar la biblioteca System.CommandLine (actualmente en versión beta) para simplificar el proceso.

En el ejemplo siguiente se muestra cómo usar argumentos de la línea de comandos en una aplicación de consola. La aplicación toma un argumento en tiempo de ejecución, lo convierte en un entero y calcula el factorial del número. Si no se proporciona ningún argumento, la aplicación emite un mensaje en el que se explica el uso correcto del programa.

Para compilar y ejecutar la aplicación desde un símbolo del sistema, siga estos pasos:

  1. Pegue el código siguiente en cualquier editor de texto, y después guarde el archivo como archivo de texto con el nombre 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. En la pantalla Inicio o en el menú Inicio, abra una ventana del Símbolo del sistema para desarrolladores de Visual Studio y navegue hasta la carpeta que contiene el archivo que creó.

  3. Escriba el siguiente comando para compilar la aplicación.

    dotnet build

    Si la aplicación no tiene ningún error de compilación, se creará un archivo ejecutable con el nombre Factorial.exe.

  4. Escriba el siguiente comando para calcular el factorial de 3:

    dotnet run -- 3

  5. El comando genera este resultado: The factorial of 3 is 6.

Nota

Al ejecutar una aplicación en Visual Studio, puede especificar argumentos de la línea de comandos en la Página Depuración, Diseñador de proyectos.

Especificación del lenguaje C#

Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.

Vea también