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

Visual C# 2010 introduce argumentos opcionales y con nombre. Los argumentos con nombre permiten especificar un argumento para un parámetro concreto asociando el argumento al nombre del parámetro y no a la posición del parámetro 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, cuando se usan conjuntamente, solo permiten especificar argumentos para algunos parámetros de una lista de parámetros opcionales. 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 la necesidad de recordar o buscar el orden de los parámetros de la lista de parámetros de los métodos llamados. El parámetro de cada argumento se puede especificar por nombre de parámetro. Por ejemplo, una función que calcula el índice de masa corporal (IMC) se puede llamar de manera estándar enviando argumentos de peso y estatura por posición en el orden que define la función.

CalculateBMI(123, 64);

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

CalculateBMI(weight: 123, height: 64);

CalculateBMI(height: 64, weight: 123);

Los argumentos con nombre también mejoran la legibilidad del código al identificar lo que cada argumento representa.

Un argumento con nombre puede seguir a los argumentos posicionales, tal y como se muestra aquí.

CalculateBMI(123, height: 64);

Pero un argumento posicional no puede seguir a un argumento con nombre. La instrucción siguiente genera un error del compilador.

//CalculateBMI(weight: 123, 64);

Ejemplo

El código siguiente implementa los ejemplos de esta sección.

class NamedExample
{
    static void Main(string[] args)
    {
        // The method can be called in the normal way, by using positional arguments.
        Console.WriteLine(CalculateBMI(123, 64));

        // Named arguments can be supplied for the parameters in either order.
        Console.WriteLine(CalculateBMI(weight: 123, height: 64));
        Console.WriteLine(CalculateBMI(height: 64, weight: 123));

        // Positional arguments cannot follow named arguments.
        // The following statement causes a compiler error.
        //Console.WriteLine(CalculateBMI(weight: 123, 64));

        // Named arguments can follow positional arguments.
        Console.WriteLine(CalculateBMI(123, height: 64));
    }

    static int CalculateBMI(int weight, int height)
    {
        return (weight * 703) / (height * height);
    }
}

Argumentos opcionales

La definición de un método, constructor, indexador o delegado puede especificar que sus parámetros son necesarios o que son 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);

    IntelliSense usa corchetes para indicar parámetros opcionales, tal y como se muestra en la ilustración siguiente.

    Información rápida de IntelliSense para el método ExampleMethod.
    Parámetros opcionales en ExampleMethod

Nota

También se pueden declarar parámetros opcionales con la clase OptionalAttribute de .NET. Los parámetros OptionalAttribute no requieren un valor predeterminado.

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("{0}: {1}, {2}, and {3}.", _name, required, optionalstr,
                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.

}

Interfaces COM

Los argumentos opcionales y con nombre, además de compatibilidad con objetos dinámicos y otros avances, 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 siguiente ilustración.

Información rápida de IntelliSense para el método AutoFormat.
Parámetros de AutoFormat

En C# 3.0 y versiones anteriores, se requiere un argumento para cada parámetro, tal y como se muestra en el ejemplo siguiente.

// In C# 3.0 and earlier versions, you need to supply an argument for
// every parameter. The following call specifies a value for the first
// parameter, and sends a placeholder value for the other six. The
// default values are used for those parameters.
var excelApp = new Microsoft.Office.Interop.Excel.Application();
excelApp.Workbooks.Add();
excelApp.Visible = true;

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

excelApp.get_Range("A1", "B4").AutoFormat(myFormat, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

Pero la llamada a AutoFormat se puede simplificar considerablemente mediante argumentos opcionales y con nombre, que se introducen en C# 4.0. 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.

// The following code shows the same call to AutoFormat in C# 4.0. Only
// the argument for which you want to provide a specific value is listed.
excelApp.Range["A1", "B4"].AutoFormat( Format: myFormat );

Para obtener más información y ejemplos, vea How to: Use Named and Optional Arguments in Office Programming [Cómo: Usar argumentos opcionales y con nombre en la programación de Office (Guía de programación de C#)] y How to: Access Office Interop Objects by Using Visual C# Features [Cómo: Tener acceso a objetos de interoperabilidad de Office mediante las características de Visual C# (Guía de programación de C#)].

Overload Resolution

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. Se trata de una consecuencia de una preferencia general en la resolución de sobrecarga para los candidatos con 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#.

Vea también

How to: Use Named and Optional Arguments in Office Programming [Cómo: Usar argumentos opcionales y con nombre en la programación de Office (Guía de programación de C#)]
Uso de tipo dinámico
Using Constructors [Uso de constructores (Guía de programación de C#)]
Utilizar indizadores