Parámetros y modificadores del método
De manera predeterminada, los argumentos de C# se pasan a funciones por valor. Esto significa que se pasa una copia de la variable al método. Para los tipos de valor (struct
), se pasa una copia del valor al método. Para los tipos de referencia (class
), se pasa una copia de la referencia al método. Los modificadores de parámetro permiten pasar argumentos por referencia.
Dado que un struct es un tipo de valor, cuando pasa un struct mediante valor a un método, el método recibe y funciona en una copia del argumento. El método no tiene acceso al struct original en el método de llamada y, por lo tanto, no puede cambiarlo de ninguna manera. El método solo puede cambiar la copia.
Una instancia de una clase es un tipo de referencia, no un tipo de valor. Cuando un tipo de referencia se pasa por valor a un método, el método recibe una copia de la referencia a la instancia. Ambas variables hacen referencia al mismo objeto. El parámetro es una copia de la referencia. El método llamado no puede reasignar la instancia en el método autor de la llamada. Sin embargo, el método llamado puede usar la copia de la referencia para acceder a los miembros de la instancia. Si el método llamado cambia un miembro de la instancia, el método autor de la llamada también ve esos cambios, ya que hace referencia a la misma instancia.
Pasar por valor y pasar por referencia
Todos los ejemplos de esta sección usan los dos tipos de record
siguientes para ilustrar las diferencias entre los tipos de class
y los tipos de struct
:
public record struct Point(int X, int Y);
// This doesn't use a primary constructor because the properties implemented for `record` types are
// readonly in record class types. That would prevent the mutations necessary for this example.
public record class Point3D
{
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
}
La salida del ejemplo siguiente ilustra la diferencia entre pasar un tipo de estructura por valor y pasar un tipo de clase por valor. Ambos métodos Mutate
cambian los valores de propiedades de su argumento. Cuando el parámetro es un tipo de struct
, esos cambios se realizan en una copia de los datos del argumento. Cuando el parámetro es un tipo de class
, esos cambios se realizan en la instancia a la que hace referencia el argumento :
public class PassTypesByValue
{
public static void Mutate(Point pt)
{
Console.WriteLine($"\tEnter {nameof(Mutate)}:\t\t{pt}");
pt.X = 19;
pt.Y = 23;
Console.WriteLine($"\tExit {nameof(Mutate)}:\t\t{pt}");
}
public static void Mutate(Point3D pt)
{
Console.WriteLine($"\tEnter {nameof(Mutate)}:\t\t{pt}");
pt.X = 19;
pt.Y = 23;
pt.Z = 42;
Console.WriteLine($"\tExit {nameof(Mutate)}:\t\t{pt}");
}
public static void TestPassTypesByValue()
{
Console.WriteLine("===== Value Types =====");
var ptStruct = new Point { X = 1, Y = 2 };
Console.WriteLine($"After initialization:\t\t{ptStruct}");
Mutate(ptStruct);
Console.WriteLine($"After called {nameof(Mutate)}:\t\t{ptStruct}");
Console.WriteLine("===== Reference Types =====");
var ptClass = new Point3D { X = 1, Y = 2, Z = 3 };
Console.WriteLine($"After initialization:\t\t{ptClass}");
Mutate(ptClass);
Console.WriteLine($"After called {nameof(Mutate)}:\t\t{ptClass}");
// Output:
// ===== Value Types =====
// After initialization: Point { X = 1, Y = 2 }
// Enter Mutate: Point { X = 1, Y = 2 }
// Exit Mutate: Point { X = 19, Y = 23 }
// After called Mutate: Point { X = 1, Y = 2 }
// ===== Reference Types =====
// After initialization: Point3D { X = 1, Y = 2, Z = 3 }
// Enter Mutate: Point3D { X = 1, Y = 2, Z = 3 }
// Exit Mutate: Point3D { X = 19, Y = 23, Z = 42 }
// After called Mutate: Point3D { X = 19, Y = 23, Z = 42 }
}
}
El modificador ref
es una manera de pasar argumentos por referencia a métodos. El código siguiente sigue el ejemplo anterior, pero pasa parámetros por referencia. Las modificaciones realizadas en el tipo struct
son visibles en el método de llamada cuando la estructura se pasa por referencia. No hay ningún cambio semántico cuando se pasa un tipo de referencia mediante referencia.
public class PassTypesByReference
{
public static void Mutate(ref Point pt)
{
Console.WriteLine($"\tEnter {nameof(Mutate)}:\t\t{pt}");
pt.X = 19;
pt.Y = 23;
Console.WriteLine($"\tExit {nameof(Mutate)}:\t\t{pt}");
}
public static void Mutate(ref Point3D pt)
{
Console.WriteLine($"\tEnter {nameof(Mutate)}:\t\t{pt}");
pt.X = 19;
pt.Y = 23;
pt.Z = 42;
Console.WriteLine($"\tExit {nameof(Mutate)}:\t\t{pt}");
}
public static void TestPassTypesByReference()
{
Console.WriteLine("===== Value Types =====");
var pStruct = new Point { X = 1, Y = 2 };
Console.WriteLine($"After initialization:\t\t{pStruct}");
Mutate(ref pStruct);
Console.WriteLine($"After called {nameof(Mutate)}:\t\t{pStruct}");
Console.WriteLine("===== Reference Types =====");
var pClass = new Point3D { X = 1, Y = 2, Z = 3 };
Console.WriteLine($"After initialization:\t\t{pClass}");
Mutate(ref pClass);
Console.WriteLine($"After called {nameof(Mutate)}:\t\t{pClass}");
// Output:
// ===== Value Types =====
// After initialization: Point { X = 1, Y = 2 }
// Enter Mutate: Point { X = 1, Y = 2 }
// Exit Mutate: Point { X = 19, Y = 23 }
// After called Mutate: Point { X = 19, Y = 23 }
// ===== Reference Types =====
// After initialization: Point3D { X = 1, Y = 2, Z = 3 }
// Enter Mutate: Point3D { X = 1, Y = 2, Z = 3 }
// Exit Mutate: Point3D { X = 19, Y = 23, Z = 42 }
// After called Mutate: Point3D { X = 19, Y = 23, Z = 42 }
}
}
En los ejemplos anteriores se modificaron las propiedades de un parámetro. Un método también puede reasignar un parámetro a un nuevo valor. La reasignación se comporta de forma diferente para los tipos de estructuras y clases cuando se pasan por valor o por referencia. En el ejemplo siguiente se muestra cómo se comportan los tipos de estructura y los tipos de clase cuando se reasignan los parámetros que se pasan por valor:
public class PassByValueReassignment
{
public static void Reassign(Point pt)
{
Console.WriteLine($"\tEnter {nameof(Reassign)}:\t\t{pt}");
pt = new Point { X = 13, Y = 29 };
Console.WriteLine($"\tExit {nameof(Reassign)}:\t\t{pt}");
}
public static void Reassign(Point3D pt)
{
Console.WriteLine($"\tEnter {nameof(Reassign)}:\t\t{pt}");
pt = new Point3D { X = 13, Y = 29, Z = -42 };
Console.WriteLine($"\tExit {nameof(Reassign)}:\t\t{pt}");
}
public static void TestPassByValueReassignment()
{
Console.WriteLine("===== Value Types =====");
var ptStruct = new Point { X = 1, Y = 2 };
Console.WriteLine($"After initialization:\t\t{ptStruct}");
Reassign(ptStruct);
Console.WriteLine($"After called {nameof(Reassign)}:\t\t{ptStruct}");
Console.WriteLine("===== Reference Types =====");
var ptClass = new Point3D { X = 1, Y = 2, Z = 3 };
Console.WriteLine($"After initialization:\t\t{ptClass}");
Reassign(ptClass);
Console.WriteLine($"After called {nameof(Reassign)}:\t\t{ptClass}");
// Output:
// ===== Value Types =====
// After initialization: Point { X = 1, Y = 2 }
// Enter Reassign: Point { X = 1, Y = 2 }
// Exit Reassign: Point { X = 13, Y = 29 }
// After called Reassign: Point { X = 1, Y = 2 }
// ===== Reference Types =====
// After initialization: Point3D { X = 1, Y = 2, Z = 3 }
// Enter Reassign: Point3D { X = 1, Y = 2, Z = 3 }
// Exit Reassign: Point3D { X = 13, Y = 29, Z = -42 }
// After called Reassign: Point3D { X = 1, Y = 2, Z = 3 }
}
}
En el ejemplo anterior se muestra que cuando se reasigna un parámetro a un nuevo valor, ese cambio no es visible desde el método que realiza la llamada, independientemente de si el tipo es un tipo de valor o un tipo de referencia. En el ejemplo siguiente se muestra el comportamiento al reasignar un parámetro que se ha pasado por referencia:
public class PassByReferenceReassignment
{
public static void Reassign(ref Point pt)
{
Console.WriteLine($"\tEnter {nameof(Reassign)}:\t\t{pt}");
pt = new Point { X = 13, Y = 29 };
Console.WriteLine($"\tExit {nameof(Reassign)}:\t\t{pt}");
}
public static void Reassign(ref Point3D pt)
{
Console.WriteLine($"\tEnter {nameof(Reassign)}:\t\t{pt}");
pt = new Point3D { X = 13, Y = 29, Z = -42 };
Console.WriteLine($"\tExit {nameof(Reassign)}:\t\t{pt}");
}
public static void TestPassByReferenceReassignment()
{
Console.WriteLine("===== Value Types =====");
var ptStruct = new Point { X = 1, Y = 2 };
Console.WriteLine($"After initialization:\t\t{ptStruct}");
Reassign(ref ptStruct);
Console.WriteLine($"After called {nameof(Reassign)}:\t\t{ptStruct}");
Console.WriteLine("===== Reference Types =====");
var ptClass = new Point3D { X = 1, Y = 2, Z = 3 };
Console.WriteLine($"After initialization:\t\t{ptClass}");
Reassign(ref ptClass);
Console.WriteLine($"After called {nameof(Reassign)}:\t\t{ptClass}");
// Output:
// ===== Value Types =====
// After initialization: Point { X = 1, Y = 2 }
// Enter Reassign: Point { X = 1, Y = 2 }
// Exit Reassign: Point { X = 13, Y = 29 }
// After called Reassign: Point { X = 13, Y = 29 }
// ===== Reference Types =====
// After initialization: Point3D { X = 1, Y = 2, Z = 3 }
// Enter Reassign: Point3D { X = 1, Y = 2, Z = 3 }
// Exit Reassign: Point3D { X = 13, Y = 29, Z = -42 }
// After called Reassign: Point3D { X = 13, Y = 29, Z = -42 }
}
}
En el ejemplo anterior se muestra cómo reasignar el valor de un parámetro que se pasa por referencia es visible en el contexto de llamada.
Contexto seguro de referencias y valores
Los métodos pueden almacenar los valores de los parámetros en campos. Cuando los parámetros se pasan por valor, normalmente es seguro. Los valores se copian y se puede acceder a los tipos de referencia cuando se almacenan en un campo. Pasar parámetros por referencia de forma segura requiere que el compilador defina cuándo es seguro asignar una referencia a una nueva variable. Para cada expresión, el compilador define un contexto seguro que enlaza el acceso a una expresión o una variable. El compilador usa dos ámbitos: safe-context y ref-safe-context.
- El ámbito safe-context define el ámbito en el que se puede acceder de forma segura a cualquier expresión.
- El ámbito ref-safe-context define el ámbito en el que se puede acceder o modificar de forma segura una referencia a cualquier expresión.
Informalmente, puede considerar estos ámbitos como un mecanismo para asegurarse de que el código nunca accede o modifica una referencia que ya no es válida. Una referencia es válida siempre que haga referencia a un objeto o estructura válidos. El ámbito safe-context define cuándo se puede asignar o reasignar una variable. El ámbito ref-safe-context define cuándo una variable se puede asignar por referencia o reasignar por referencia. La asignación asigna una variable a un nuevo valor; la asignación por referencia asigna la variable para hacer referencia a otra ubicación de almacenamiento.
Parámetros de referencia
Se aplica uno de los modificadores siguientes a una declaración de parámetro para pasar argumentos por referencia en lugar de por valor:
ref
: el argumento se debe inicializar antes de llamar al método. El método puede asignar un nuevo valor al parámetro, pero no es necesario hacerlo.out
: el método autor de la llamada no tiene que inicializar el argumento antes de llamar al método. El método debe asignar un valor al parámetro.ref readonly
: el argumento se debe inicializar antes de llamar al método. El método no puede asignar un nuevo valor al parámetro.in
: el argumento se debe inicializar antes de llamar al método. El método no puede asignar un nuevo valor al parámetro. El compilador puede crear una variable temporal para contener una copia del argumento en los parámetrosin
.
Un parámetro que se pasa por referencia es una variable de referencia . No tiene su propio valor. En su lugar, hace referencia a una variable diferente denominada su referente. Las variables de referencia pueden ser ref reasignadas, lo que cambia su objeto de referencia.
Los miembros de una clase no pueden tener signaturas que se diferencien solo por ref
, ref readonly
, in
o out
. Si la única diferencia entre dos miembros de un tipo es que uno de ellos tiene un parámetro ref
y el otro tiene un parámetro out
, ref readonly
o in
, se produce un error de compilador. En cambio, los métodos se pueden sobrecargar cuando un método tiene un parámetro ref
, ref readonly
, in
o out
, y el otro tiene un parámetro que se pasa por valor, como se muestra en el ejemplo siguiente. En otras situaciones que requieran signatura coincidente, como ocultar o reemplazar, in
, ref
, ref readonly
y out
forman parte de la signatura y no coinciden entre sí.
Cuando un parámetro tiene uno de los modificadores anteriores, el argumento correspondiente puede tener un modificador compatible:
- Un argumento de un parámetro
ref
debe incluir el modificadorref
. - Un argumento de un parámetro
out
debe incluir el modificadorout
. - Un argumento de un parámetro
in
puede incluir opcionalmente el modificadorin
. Si, en su lugar, se usa en el argumento el modificadorref
, el compilador emite una advertencia. - Un argumento de un parámetro
ref readonly
debe incluir los modificadoresin
oref
, pero no ambos. Si no se incluye ninguno de los modificadores, el compilador emite una advertencia.
Al usar estos modificadores, describen cómo se usa el argumento:
ref
significa que el método puede leer o escribir el valor del argumento.out
significa que el método establece el valor del argumento.ref readonly
significa que el método lee, pero no puede escribir, el valor del argumento. El argumento se debe pasar por referencia.in
significa que el método lee, pero no puede escribir, el valor del argumento. El argumento se pasará por referencia o mediante una variable temporal.
No puede usar los modificadores de parámetros anteriores en los siguientes tipos de métodos:
- Métodos asincrónicos, que se definen mediante el uso del modificador async.
- Métodos de iterador, que incluyen una instrucción yield return o
yield break
.
Los métodos de extensión también tienen restricciones en el uso de estas palabras clave en los argumentos:
- No se puede usar la palabra clave
out
en el primer argumento de un método de extensión. - No se puede usar la palabra clave
ref
en el primer argumento de un método de extensión cuando el argumento no es de tipostruct
ni un tipo genérico no restringido para ser de tipo struct. - No se pueden usar las palabras claves
ref readonly
ein
a menos que el primer argumento sea de tipostruct
. - No se pueden usar las palabras clave
ref readonly
ein
en ningún tipo genérico, incluso cuando está restringido para ser de tipo struct.
Las propiedades no son variables. Son métodos. Las propiedades no pueden ser argumentos para ref
parámetros.
ref
(modificador de parámetro)
Para usar un parámetro ref
, la definición de método y el método de llamada deben utilizar explícitamente la palabra clave ref
, como se muestra en el ejemplo siguiente. (Salvo que el método de llamada puede omitir ref
al realizar una llamada COM).
void Method(ref int refArgument)
{
refArgument = refArgument + 44;
}
int number = 1;
Method(ref number);
Console.WriteLine(number);
// Output: 45
Un argumento que se pasa a un parámetro ref
se debe inicializar antes de pasarlo.
out
(modificador de parámetro)
Para usar un parámetro out
, tanto la definición de método como el método de llamada deben utilizar explícitamente la palabra clave out
. Por ejemplo:
int initializeInMethod;
OutArgExample(out initializeInMethod);
Console.WriteLine(initializeInMethod); // value is now 44
void OutArgExample(out int number)
{
number = 44;
}
Las variables que se han pasado como argumentos out
no tienen que inicializarse antes de pasarse en una llamada al método. En cambio, se necesita el método que se ha llamado para asignar un valor antes de que el método se devuelva.
Los métodos de deconstrucción declaran sus parámetros con el modificador out
para devolver varios valores. Otros métodos pueden devolver tuplas de valores para varios valores devueltos.
Puede declarar una variable en una instrucción independiente antes de pasarla como un argumento out
. También puede declarar la variable out
en la lista de argumentos de la llamada de método, en lugar de en una declaración de variable independiente. Las declaraciones de variables out
generan un código legible más compacto y, además, evitan que asigne un valor a la variable antes de la llamada al método de manera involuntaria. El ejemplo siguiente define la variable number
en la llamada al método Int32.TryParse.
string numberAsString = "1640";
if (Int32.TryParse(numberAsString, out int number))
Console.WriteLine($"Converted '{numberAsString}' to {number}");
else
Console.WriteLine($"Unable to convert '{numberAsString}'");
// The example displays the following output:
// Converted '1640' to 1640
También puede declarar una variable local con tipo implícito.
Modificador ref readonly
El modificador ref readonly
debe estar presente en la declaración del método. Un modificador en el sitio de llamada es opcional. Se puede usar el modificador in
o ref
. El modificador ref readonly
no es válido en el sitio de llamada. El modificador que se usa en el sitio de llamada puede ayudar a describir las características del argumento. Solo puede usar ref
si el argumento es una variable y se puede escribir. Solo puede usar in
cuando el argumento es una variable. Puede ser de escritura o de solo lectura. No se puede agregar ningún modificador si el argumento no es una variable, sino una expresión. En los ejemplos siguientes, se muestran estas condiciones. El método siguiente usa el modificador ref readonly
para indicar que una estructura grande se debe pasar por referencia por motivos de rendimiento:
public static void ForceByRef(ref readonly OptionStruct thing)
{
// elided
}
Puede llamar al método mediante el modificador ref
o in
. Si omite el modificador, el compilador emite una advertencia. Cuando el argumento es una expresión, no una variable, no se pueden agregar los modificadores in
ni ref
, por lo que debe suprimir la advertencia:
ForceByRef(in options);
ForceByRef(ref options);
ForceByRef(options); // Warning! variable should be passed with `ref` or `in`
ForceByRef(new OptionStruct()); // Warning, but an expression, so no variable to reference
Si la variable es una variable readonly
, debe usar el modificador in
. El compilador emite un error si usa el modificador ref
en su lugar.
El modificador ref readonly
indica que el método espera que el argumento sea una variable en lugar de una expresión que no sea una variable. Algunos ejemplos de expresiones que no son variables son las constantes, los valores devueltos de un método y las propiedades. Si el argumento no es una variable, el compilador emite una advertencia.
in
(modificador de parámetro)
El modificador in
es necesario en la declaración del método, pero no es necesario en el sitio de llamada.
int readonlyArgument = 44;
InArgExample(readonlyArgument);
Console.WriteLine(readonlyArgument); // value is still 44
void InArgExample(in int number)
{
// Uncomment the following line to see error CS8331
//number = 19;
}
El modificador in
permite al compilador crear una variable temporal para el argumento y pasar una referencia de solo lectura a ese argumento. El compilador siempre crea una variable temporal cuando se debe convertir el argumento, cuando hay una conversión implícita del tipo de argumento o cuando el argumento es un valor que no es una variable. Por ejemplo, cuando el argumento es un valor literal o el valor devuelto desde el descriptor de acceso de una propiedad. Cuando la API requiera que el argumento se pase por referencia, elija el modificador ref readonly
en lugar del modificador in
.
Los métodos definidos mediante parámetros in
pueden obtener una optimización del rendimiento. Algunos argumentos de tipo struct
pueden tener un gran tamaño y, cuando se llama a métodos en bucles de pequeñas dimensiones o rutas de acceso de código crítico, el costo de copiar esas estructuras resulta importante. Los métodos declaran parámetros in
para especificar qué argumentos se pueden pasar por referencia sin ningún riesgo porque el método llamado no modifica el estado de ese argumento. Al pasar esos argumentos por referencia se evita la copia (potencialmente) costosa. Se agrega explícitamente el modificador in
en el sitio de llamada para garantizar que el argumento se pasa por referencia, y no por valor. Usar explícitamente in
tiene los dos efectos siguientes:
- Al especificar
in
en el sitio de llamada, se fuerza al compilador a seleccionar un método definido con un parámetroin
coincidente. En caso contrario, cuando dos métodos se diferencian solo en presencia dein
, la sobrecarga por valor es una coincidencia mejor. - Al especificar
in
, declara su intención de pasar un argumento por referencia. Los argumentos usados conin
deben representar una ubicación a la que se pueda hacer referencia directamente. Se aplican las mismas reglas generales para los argumentosout
yref
: no se pueden usar constantes, propiedades normales u otras expresiones que produzcan valores. En caso contrario, si se omitein
en el sitio de llamada, se informa al compilador de que le permitirá crear una variable temporal para pasar por referencia de solo lectura al método. El compilador crea una variable temporal para superar varias restricciones con argumentosin
:- Una variable temporal permite constantes en tiempo de compilación como parámetros
in
. - Una variable temporal permite propiedades u otras expresiones para parámetros
in
. - Una variable temporal permite argumentos en los que hay una conversión implícita desde el tipo de argumento hacia el tipo de parámetro.
- Una variable temporal permite constantes en tiempo de compilación como parámetros
En todas las instancias anteriores, el compilador crea una variable temporal que almacena el valor de la constante, la propiedad u otra expresión.
Estas reglas se muestran en este código:
static void Method(in int argument)
{
// implementation removed
}
Method(5); // OK, temporary variable created.
Method(5L); // CS1503: no implicit conversion from long to int
short s = 0;
Method(s); // OK, temporary int created with the value 0
Method(in s); // CS1503: cannot convert from in short to in int
int i = 42;
Method(i); // passed by readonly reference
Method(in i); // passed by readonly reference, explicitly using `in`
Supongamos ahora que hay disponible otro método que usa argumentos por valor. Los resultados cambian como se muestra en este código:
static void Method(int argument)
{
// implementation removed
}
static void Method(in int argument)
{
// implementation removed
}
Method(5); // Calls overload passed by value
Method(5L); // CS1503: no implicit conversion from long to int
short s = 0;
Method(s); // Calls overload passed by value.
Method(in s); // CS1503: cannot convert from in short to in int
int i = 42;
Method(i); // Calls overload passed by value
Method(in i); // passed by readonly reference, explicitly using `in`
La única llamada de método donde se pasa el argumento por referencia es la última.
Nota:
El código anterior usa int
como el tipo de argumento para simplificar el trabajo. Como int
no es más grande que una referencia en la mayoría de máquinas modernas, no supone ninguna ventaja pasar un único int
como una referencia de solo lectura.
Modificador params
No se permiten otros parámetros después de la palabra clave params
en una declaración de método, y solo se permite una palabra clave params
en una declaración de método.
El tipo declarado del parámetro params
debe ser un tipo de colección. Los tipos de colección reconocidos son los siguientes:
- Un tipo de matriz unidimensional
T[]
, en cuyo caso el tipo de elemento esT
. - Tipo de intervalo:
System.Span<T>
System.ReadOnlySpan<T>
Aquí, el tipo de elemento esT
.
- Tipo con un método de creación accesible con un tipo de elemento correspondiente. El método de creación se identifica mediante el mismo atributo que se usa para las expresiones de colección.
- Un tipo de clase o estructura que implementa System.Collections.Generic.IEnumerable<T> donde:
- El tipo tiene un constructor que se puede invocar sin argumentos y el constructor es al menos tan accesible como el miembro declarante.
- El tipo tiene un método de instancia
Add
(no una extensión) donde:- El método se puede invocar con un único argumento de valor.
- Si el método es genérico, los argumentos de tipo se pueden deducir del argumento.
- El método es al menos tan accesible como el miembro declarante. Aquí, el tipo de elemento es el tipo de iteración del tipo.
- Tipo de interfaz:
Antes de C# 13, el parámetro debe ser una matriz unidimensional.
Cuando se llama a un método con un parámetro params
, se puede pasar:
- Una lista separada por comas de argumentos del tipo de los elementos de la matriz.
- Colección de argumentos del tipo especificado.
- Sin argumentos. Si no envía ningún argumento, la longitud de la lista
params
es cero.
En el ejemplo siguiente se muestran varias maneras de enviar argumentos a un parámetro params
.
public static void ParamsModifierExample(params int[] list)
{
for (int i = 0; i < list.Length; i++)
{
System.Console.Write(list[i] + " ");
}
System.Console.WriteLine();
}
public static void ParamsModifierObjectExample(params object[] list)
{
for (int i = 0; i < list.Length; i++)
{
System.Console.Write(list[i] + " ");
}
System.Console.WriteLine();
}
public static void TryParamsCalls()
{
// You can send a comma-separated list of arguments of the
// specified type.
ParamsModifierExample(1, 2, 3, 4);
ParamsModifierObjectExample(1, 'a', "test");
// A params parameter accepts zero or more arguments.
// The following calling statement displays only a blank line.
ParamsModifierObjectExample();
// An array argument can be passed, as long as the array
// type matches the parameter type of the method being called.
int[] myIntArray = { 5, 6, 7, 8, 9 };
ParamsModifierExample(myIntArray);
object[] myObjArray = { 2, 'b', "test", "again" };
ParamsModifierObjectExample(myObjArray);
// The following call causes a compiler error because the object
// array cannot be converted into an integer array.
//ParamsModifierExample(myObjArray);
// The following call does not cause an error, but the entire
// integer array becomes the first element of the params array.
ParamsModifierObjectExample(myIntArray);
}
/*
Output:
1 2 3 4
1 a test
5 6 7 8 9
2 b test again
System.Int32[]
*/
La resolución de sobrecargas puede provocar ambigüedad cuando el argumento de un params
parámetro es un tipo de colección. El tipo de colección del argumento debe ser convertible al tipo de colección del parámetro . Cuando diferentes sobrecargas proporcionan mejores conversiones para ese parámetro, ese método podría ser mejor. Sin embargo, si el argumento para el params
parámetro es elementos discretos o falta, todas las sobrecargas con tipos de parámetros diferentes params
son iguales para ese parámetro.
Para obtener más información, consulte la sección Listas de argumentos de Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.