Un parámetro sin ref, sin salida, como una variable local, denota una ubicación de almacenamiento. Si el tipo de ubicación de almacenamiento es un tipo de referencia, la ubicación de almacenamiento contiene una referencia a una instancia de ese tipo.
Los parámetros de referencia y de rechazo, por el contrario, mantienen una referencia a una ubicación de almacenamiento. Esa ubicación de almacenamiento podría ser una variable local, un campo o un elemento de matriz. En otras palabras, los parámetros ref y out presentan otra capa de indirección. Si tiene un parámetro ref o out de tipo referencia en un método, por lo tanto, representa una referencia a una referencia a un objeto.
¿Por qué querría una referencia a una referencia a un objeto? En caso de que necesite modificar la referencia al objeto (en lugar de modificar el objeto en sí).
Esta es una técnica útil en algunas circunstancias limitadas.Por ejemplo, es posible que desee escribir una función que ordena dos colas dependiendo de que tiene el valor más pequeño en la parte superior:
void OrderQueues(ref Queue<int> a, ref Queue<int> b)
{
if (a.Peek <= b.Peek) return;
var temp = a;
a = b;
b = temp;
}
Parámetros que son útiles si desea devolver más de un valor a partir de un método:
void OldestAndYoungest(IEnumerable<Person> people, out Person youngest, out Person oldest)
{
youngest = null;
oldest = null;
foreach (var person in people)
{
if (youngest == null || person.Age < youngest.Age)
youngest = person;
if (oldest == null || oldest.Age < person.Age)
oldest = person;
}
}
En mi experiencia, los parámetros de ref y out son bastante raros, y aún más raros con los tipos de referencia.
Tenga en cuenta que un parámetro ref debe ser inicializado por la persona que llama, mientras que un parámetro de salida debe ser inicializado por el destinatario. Si nunca le asigna un valor al parámetro ref, entonces probablemente debería ser un parámetro "normal". Si nunca le asigna un valor a un parámetro out, como en su ejemplo, su código no se compilará.