Argumentos opcionales y con nombre (Guía de programación de C#)

Los argumentos con nombre permiten especificar un argumento para un parámetro asociando el argumento a su nombre y no a su posición en la lista de parámetros. Los argumentos opcionales permiten omitir argumentos para algunos parámetros. Ambas técnicas se pueden usar con métodos, indexadores, constructores y delegados.

Cuando se usan argumentos opcionales y con nombre, los argumentos se evalúan por el orden en que aparecen en la lista de argumentos, no en la lista de parámetros.

Los parámetros opcionales y con nombre permiten proporcionar argumentos para los parámetros seleccionados. Esta funcionalidad facilita enormemente las llamadas a interfaces COM, como las API de automatización de Microsoft Office.

Argumentos con nombre

Los argumentos con nombre le liberan de hacer coincidir el orden de los argumentos con el de los parámetros en las listas de parámetros de los métodos llamados. El argumento de cada parámetro se puede especificar por el nombre del parámetro. Por ejemplo, se puede llamar a una función que imprime los detalles de un pedido (como por ejemplo, el nombre de vendedor, el nombre de producto y el número del pedido) mediante el envío de argumentos por posición, en el orden definido por la función.

PrintOrderDetails("Gift Shop", 31, "Red Mug");

Si no recuerda el orden de los parámetros pero conoce sus nombres, puede enviar los argumentos en cualquier orden.

PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");
PrintOrderDetails(productName: "Red Mug", sellerName: "Gift Shop", orderNum: 31);

Los argumentos con nombre también mejoran la legibilidad del código al identificar lo que cada argumento representa. En el método de ejemplo siguiente, sellerName no puede ser nulo ni un espacio en blanco. Como sellerName y productName son tipos de cadena, en lugar de enviar argumentos por posición, tiene sentido usar argumentos con nombre para eliminar la ambigüedad entre ambos y evitar confusiones para aquellos que lean el código.

Los argumentos con nombre, cuando se usan con argumentos posicionales, son válidos siempre que

  • no vayan seguidos de ningún argumento posicional o,

    PrintOrderDetails("Gift Shop", 31, productName: "Red Mug");
    
  • se usen en la posición correcta. En este ejemplo, el parámetro orderNum está en la posición correcta pero no se le asigna un nombre de manera explícita.

    PrintOrderDetails(sellerName: "Gift Shop", 31, productName: "Red Mug");
    

Los argumentos posicionales que siguen a los argumentos con nombre desordenados no son válidos.

// This generates CS1738: Named argument specifications must appear after all fixed arguments have been specified.
PrintOrderDetails(productName: "Red Mug", 31, "Gift Shop");

Ejemplo

Con este código se implementan los ejemplos de esta sección junto con otros adicionales.

class NamedExample
{
    static void Main(string[] args)
    {
        // The method can be called in the normal way, by using positional arguments.
        PrintOrderDetails("Gift Shop", 31, "Red Mug");

        // Named arguments can be supplied for the parameters in any order.
        PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");
        PrintOrderDetails(productName: "Red Mug", sellerName: "Gift Shop", orderNum: 31);

        // Named arguments mixed with positional arguments are valid
        // as long as they are used in their correct position.
        PrintOrderDetails("Gift Shop", 31, productName: "Red Mug");
        PrintOrderDetails(sellerName: "Gift Shop", 31, productName: "Red Mug"); 
        PrintOrderDetails("Gift Shop", orderNum: 31, "Red Mug");

        // However, mixed arguments are invalid if used out-of-order.
        // The following statements will cause a compiler error.
        // PrintOrderDetails(productName: "Red Mug", 31, "Gift Shop");
        // PrintOrderDetails(31, sellerName: "Gift Shop", "Red Mug");
        // PrintOrderDetails(31, "Red Mug", sellerName: "Gift Shop");
    }

    static void PrintOrderDetails(string sellerName, int orderNum, string productName)
    {
        if (string.IsNullOrWhiteSpace(sellerName))
        {
            throw new ArgumentException(message: "Seller name cannot be null or empty.", paramName: nameof(sellerName));
        }

        Console.WriteLine($"Seller: {sellerName}, Order #: {orderNum}, Product: {productName}");
    }
}

Argumentos opcionales

La definición de un método, constructor, indexador o delegado puede especificar que sus parámetros son necesarios u opcionales. Todas las llamadas deben proporcionar argumentos para todos los parámetros necesarios, pero pueden omitir los argumentos para los parámetros opcionales.

Cada parámetro opcional tiene un valor predeterminado como parte de su definición. Si no se envía ningún argumento para ese parámetro, se usa el valor predeterminado. Un valor predeterminado debe ser uno de los siguientes tipos de expresiones:

  • una expresión constante;
  • una expresión con el formato new ValType(), donde ValType es un tipo de valor, como enum o struct;
  • una expresión con el formato default(ValType), donde ValType es un tipo de valor.

Los parámetros opcionales se definen al final de la lista de parámetros después de los parámetros necesarios. Si el autor de la llamada proporciona un argumento para algún parámetro de una sucesión de parámetros opcionales, debe proporcionar argumentos para todos los parámetros opcionales anteriores. No se admiten espacios separados por comas en la lista de argumentos. Por ejemplo, en el código siguiente, el método de instancia ExampleMethod se define con un parámetro necesario y dos opcionales.

public void ExampleMethod(int required, string optionalstr = "default string",
    int optionalint = 10)

La llamada siguiente a ExampleMethod genera un error del compilador, porque se proporciona un argumento para el tercer parámetro pero no para el segundo.

//anExample.ExampleMethod(3, ,4);

Pero si conoce el nombre del tercer parámetro, puede usar un argumento con nombre para realizar la tarea.

anExample.ExampleMethod(3, optionalint: 4);

En IntelliSense los corchetes se usan para indicar parámetros opcionales, como se muestra en la ilustración siguiente:

Captura de pantalla en la que se muestra información rápida de IntelliSense para el método ExampleMethod.

Nota

También puede declarar parámetros opcionales con la clase OptionalAttribute de .NET. Los parámetros OptionalAttribute no requieren un valor predeterminado. Sin embargo, si se desea un valor predeterminado, eche un vistazo a la clase DefaultParameterValueAttribute.

Ejemplo

En el ejemplo siguiente, el constructor de ExampleClass tiene un solo parámetro, que es opcional. El método de instancia ExampleMethod tiene un parámetro necesario, required, y dos parámetros opcionales, optionalstr y optionalint. El código de Main muestra las distintas formas en que se pueden invocar el constructor y el método.

namespace OptionalNamespace
{
    class OptionalExample
    {
        static void Main(string[] args)
        {
            // Instance anExample does not send an argument for the constructor's
            // optional parameter.
            ExampleClass anExample = new ExampleClass();
            anExample.ExampleMethod(1, "One", 1);
            anExample.ExampleMethod(2, "Two");
            anExample.ExampleMethod(3);

            // Instance anotherExample sends an argument for the constructor's
            // optional parameter.
            ExampleClass anotherExample = new ExampleClass("Provided name");
            anotherExample.ExampleMethod(1, "One", 1);
            anotherExample.ExampleMethod(2, "Two");
            anotherExample.ExampleMethod(3);

            // The following statements produce compiler errors.

            // An argument must be supplied for the first parameter, and it
            // must be an integer.
            //anExample.ExampleMethod("One", 1);
            //anExample.ExampleMethod();

            // You cannot leave a gap in the provided arguments.
            //anExample.ExampleMethod(3, ,4);
            //anExample.ExampleMethod(3, 4);

            // You can use a named parameter to make the previous
            // statement work.
            anExample.ExampleMethod(3, optionalint: 4);
        }
    }

    class ExampleClass
    {
        private string _name;

        // Because the parameter for the constructor, name, has a default
        // value assigned to it, it is optional.
        public ExampleClass(string name = "Default name")
        {
            _name = name;
        }

        // The first parameter, required, has no default value assigned
        // to it. Therefore, it is not optional. Both optionalstr and
        // optionalint have default values assigned to them. They are optional.
        public void ExampleMethod(int required, string optionalstr = "default string",
            int optionalint = 10)
        {
            Console.WriteLine(
                $"{_name}: {required}, {optionalstr}, and {optionalint}.");
        }
    }

    // The output from this example is the following:
    // Default name: 1, One, and 1.
    // Default name: 2, Two, and 10.
    // Default name: 3, default string, and 10.
    // Provided name: 1, One, and 1.
    // Provided name: 2, Two, and 10.
    // Provided name: 3, default string, and 10.
    // Default name: 3, default string, and 4.
}

En el código anterior se muestran varios ejemplos en los que los parámetros opcionales no se aplican correctamente. En primer lugar, se muestra que se debe proporcionar un argumento para el primer parámetro, que es obligatorio.

Atributos de información del autor de la llamada

Los atributos de información del autor de la llamada, como CallerFilePathAttribute, CallerLineNumberAttribute, CallerMemberNameAttribute y CallerArgumentExpressionAttribute, se usan para obtener información sobre el autor de la llamada a un método. Estos atributos son especialmente útiles cuando se depura o cuando se necesita registrar información sobre las llamadas de método.

Estos atributos son parámetros opcionales con valores predeterminados que proporciona el compilador. El autor de la llamada no debe proporcionar explícitamente un valor para estos parámetros.

Interfaces COM

Los argumentos opcionales y con nombre, además de compatibilidad con objetos dinámicos, mejoran considerablemente la interoperabilidad con las API de COM, como las API de automatización de Office.

Por ejemplo, el método AutoFormat de la interfaz Range de Microsoft Office Excel tiene siete parámetros, todos ellos opcionales. Estos parámetros se muestran en la ilustración siguiente:

Captura de pantalla en la que se muestra información rápida de IntelliSense para el método AutoFormat.

Pero la llamada a AutoFormat se puede simplificar considerablemente mediante argumentos opcionales y con nombre. Los parámetros opcionales y con nombre permiten omitir el argumento de un parámetro opcional si no se quiere cambiar el valor predeterminado del parámetro. En la siguiente llamada, solo se especifica un valor para uno de los siete parámetros.

var excelApp = new Microsoft.Office.Interop.Excel.Application();
excelApp.Workbooks.Add();
excelApp.Visible = true;

var myFormat =
    Microsoft.Office.Interop.Excel.XlRangeAutoFormat.xlRangeAutoFormatAccounting1;

excelApp.Range["A1", "B4"].AutoFormat( Format: myFormat );

Para obtener más información y ejemplos, vea Procedimiento para usar argumentos opcionales y con nombre en la programación de Office (Guía de programación de C#) y Procedimiento para tener acceso a objetos de interoperabilidad de Office mediante las características de Visual C# (Guía de programación de C#).

Resolución de sobrecarga

El uso de argumentos opcionales y con nombre afecta a la resolución de sobrecarga de las maneras siguientes:

  • Un método, indexador o constructor es un candidato para la ejecución si cada uno de sus parámetros es opcional o corresponde, por nombre o por posición, a un solo argumento de la instrucción de llamada y el argumento se puede convertir al tipo del parámetro.
  • Si se encuentra más de un candidato, se aplican las reglas de resolución de sobrecarga de las conversiones preferidas a los argumentos que se especifican explícitamente. Los argumentos omitidos en parámetros opcionales se ignoran.
  • Si dos candidatos se consideran igualmente correctos, la preferencia pasa a un candidato que no tenga parámetros opcionales cuyos argumentos se hayan omitido en la llamada. Generalmente, la resolución de sobrecarga prefiere aquellos candidatos que tengan menos parámetros.

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#.