Parámetros Línea de Comandos. C Sharp
SOLUCIONARIO
Parámetros Línea de Comandos. C Sharp
2026-02-08
Por
Occam's Razor

using System;

class cmdline {
    static void Main (string[] arg) {
    Console.WriteLine (System.AppDomain.CurrentDomain.FriendlyName);
    Console.WriteLine ($"{arg.Length} parámetros");
    
    for (int i = 0; i < arg.Length; i++)
        Console.WriteLine ($"Parámetro {i} -> {arg[i]}");
    if (arg.Length != 1) {
        Console.WriteLine ("Solo un parámetro por favor");
        return;
    }
    Console.WriteLine ($"Hola {arg[0]}");
    }
}
    

C# nos ofrece exactamente el mismo interfaz que Java. Los parámetros se pasan en una matriz de cadenas de caracteres al método llamado Main de la clase principal del programa.

La matriz de parámetros solo contiene los parámetros y no el nombre del programa como primer elemento tal y como hemos visto en otros lenguajes.

SABIAS QUE

El nombre del ejecutable se almacena en:

System.AppDomain.CurrentDomain.FriendlyName

Alternativamente podemos acceder a los arguments tal y como los recibimos en los programas C/C++, ejecutando el siguiente método:

Environment.GetCommandLineArgs()

Como ya podemos esperar, existen varios paquetes con los que procesar los argumentos de forma más fácil y potente. Al igual que me ha sucedido con Rust, hacer que los módulos funcionen ha sido bastante frustrante, al menos en una Debian 12 estándar usando mono.

SOY NOVATO

Al parecer la forma más segura de evitar este tipo de problemas es usar el entorno dotnet proporcionado por Microsoft.

Entre las posibles opciones decidí utilizar el paquete Options que ofrece una funcionalidad muy similar a getopts, el cual conocemos muy bien a estas alturas. Al parecer existía un paquete en Debian llamado libmono-options-cil, pero parece que ya no está disponible, así que la mejor opción para poder usar este paquete, es descargar las fuentes directamente del repositorio de mono, usando el siguiente comando.

wget httpx://raw.githubusercontent.com/mono/mono/refs/heads/main/mcs/class/Mono.Options/Mono.Options/Options.cs

Ahora que disponemos del módulo para procesar los parámetros, podemos escribir nuestro programa, el cual, estoy seguro, que os resultará familiar.

using System;
using System.Collections.Generic;
using Mono.Options;

class Program
{
  static void Main(string[] args)
  {
    bool showHelp = false;
    string inputFile = "input.txt";
    string outputFile = "output.txt";
    
    var options = new OptionSet
    {
        { "h|help", "show this message and exit", h => showHelp = (h != null) },
        { "i|input=", "input file (default: input.txt)", i => inputFile = i },
        { "o|output=", "output file (default: output.txt)", o => outputFile = o },
    };

    List<string> extraArgs;
    try
    {
      extraArgs = options.Parse(args);
    }
    catch (OptionException e)
    {
      Console.WriteLine(e.Message);
      Console.WriteLine("Try `--help` for more information.");
      return;
    }

    if (showHelp)
    {
      Console.WriteLine("Usage: app [OPTIONS]");
      Console.WriteLine();
      Console.WriteLine("Options:");
      options.WriteOptionDescriptions(Console.Out);

    return;
    }
    Console.WriteLine($"Input file : {inputFile}");
    Console.WriteLine($"Output file: {outputFile}");
  }
}

El módulo utiliza la clase OptionSet para definir los flags que esperamos procesar. Como podéis ver, podemos definir flags cortos así como indicar si esperamos parámetros obligatorios (añadiendo = tras el nombre del flag) u opcionales (añadiendo : tras el nombre del flag).

El último campo de los elementos OptionSet es una función. En este caso, para hacer el código más pequeño hemos utilizado expresiones lambda. Para cada posible opción inicializamos las variables que necesitamos y poco más.

SOY NOVATO

Aunque ya hablaremos las funciones lambda cuando hablemos de funciones, para poder entender el programa. La expresión:

i => inputFile = i

Es equivalente a una función que recibe un parámetro llamado i y asigna su valor a la variable inputFile.

static void SetInput(string o) {
  inputFile = o;
}

En este caso, dejando a un lado, los cambios necesarios para poder modificar inputFile desde la función (lo más fácil es hacer todas las variables y funciones static, la declaración del OptionSet correspondiente sería:

{ "i|input=", "input file (default: input.txt)", SetInput},

El parseado de los parámetros lo realiza el método Parse, el cual procesará la entrada según lo que hayamos especificado en nuestro OptionSet y producirá una excepción si encuentra cualquier error. Además, Parse nos devuelve cualquier parámetro adicional, no incluido en el OptionSet que encuentre. Útil para utilidades que esperan varios nombres de ficheros por ejemplo.

Resumen

  • C# recibe los argumentos de la línea de comandos como un array de cadenas
  • C# no incluye el nombre del programa en el primer elemento del array de argumentos
  • El paquete Option nos permite procesar los argumentos de forma sencilla y muy similar a como lo hace el paquete getopt estándar.

SOBRE Occam's Razor
Somos una revista libre que intenta explicar de forma sencilla conceptos tecnológicos y científicos de los que no podemos escapar. Al final, todo es más fácil de lo que parece!

 
Tu publicidad aquí :)