tag see remarks net method generate example cref c# c#-4.0 argument-passing ref

remarks - see cref c#



¿Por qué se lista cuando se pasa sin ref a una función que actúa como aprobada con ref? (7)

ByRef y ByVal solo se aplican a tipos de valores, no a tipos de referencia, que siempre se pasan como si fueran "byref".

Si necesita modificar una lista discretamente, use la función ".ToList ()" y obtendrá una clonación de su lista.

Tenga en cuenta que si su lista contiene tipos de referencia, su lista "nueva" contiene punteros a los mismos objetos que su lista original.

Si no entendí esto terriblemente mal, este comportamiento es extraño para mí. En lugar de explicarlo, publicaré un código de muestra a continuación y, por favor, díganme por qué obtengo la salida xy no y.

private void button1_Click(object sender, EventArgs e) { List<int> l = new List<int>() { 1, 2, 3 }; Fuss(l); MessageBox.Show(l.Count.ToString()); } private void Fuss(List<int> l) { l.Add(4); l.Add(5); }

La salida debería, supongo que sería 3. Pero obtengo la salida como 5. Entiendo que la salida puede ser 5 si hago esto:

private void button1_Click(object sender, EventArgs e) { List<int> l = new List<int>() { 1, 2, 3 }; Fuss(ref l); MessageBox.Show(l.Count.ToString()); } private void Fuss(ref List<int> l) { l.Add(4); l.Add(5); }


La diferencia entre ref y no ref para tipos de referencia como List no es si pasa una referencia (eso siempre ocurre), sino si se puede cambiar esa referencia. Pruebe lo siguiente

private void Fuss(ref List<int> l) { l = new List<int> { 4, 5 }; }

y verá que el recuento es 2, porque la función no solo manipuló la lista original sino la referencia misma.


Las listas ya son tipos de referencia, por lo que cuando las pasa a un método, está pasando una referencia. Cualquier llamada Add afectará la lista en la persona que llama.

Pasar una List<T> por ref comporta esencialmente como pasar un doble puntero a esa lista. Aquí hay una ilustración:

using System; using System.Collections.Generic; public class Test { public static void Main() { List<int> l = new List<int>() { 1, 2, 3 }; Fuss(l); Console.WriteLine(l.Count); // Count will now be 5. FussNonRef(l); Console.WriteLine(l.Count); // Count will still be 5 because we // overwrote the copy of our reference // in FussNonRef. FussRef(ref l); Console.WriteLine(l.Count); // Count will be 2 because we changed // our reference in FussRef. } private static void Fuss(List<int> l) { l.Add(4); l.Add(5); } private static void FussNonRef(List<int> l) { l = new List<int>(); l.Add(6); l.Add(7); } private static void FussRef(ref List<int> l) { l = new List<int>(); l.Add(8); l.Add(9); } }


Los parámetros se pasan por valor en C # a menos que estén marcados con los modificadores ref o out . Para los tipos de referencia, esto significa que la referencia se pasa por valor. Por lo tanto, en Fuss , me refiero a la misma instancia de List<int> que su llamador. Por lo tanto, cualquier modificación a esta instancia de List<int> será vista por la persona que llama.

Ahora, si marca el parámetro l con ref o out , el parámetro se pasa por referencia. Lo que esto significa es que en Fuss , l es un alias para la ubicación de almacenamiento utilizada como parámetro para invocar el método. Para ser claro:

public void Fuss(ref List<int> l)

llamado por

List<int> list = new List<int> { 1, 2, 3 }; Fuss(list);

Ahora, en Fuss , l un alias para la list . En particular, si asigna una nueva instancia de List<int> a l , la persona que llama verá también esa nueva instancia asignada a la list variables. En particular, si dices

public void Fuss(ref List<int> l) { l = new List<int> { 1 }; }

entonces la persona que llama ahora verá una lista con un elemento. Pero si dices

public void Fuss(List<int> l) { l = new List<int> { 1 }; }

y llamar por

List<int> list = new List<int> { 1, 2, 3 }; Fuss(list);

entonces la persona que llama aún verá la list como si tuviera tres elementos.

¿Claro?


No actúa como si fuera aprobado por ref.

void ChangeMe(List<int> list) { list = new List<int>(); list.Add(10); } void ChangeMeReally(ref List<int> list) { list = new List<int>(); list.Add(10); }

Intentalo. ¿Notaste la diferencia?

Solo puede cambiar los contenidos de la lista (o cualquier tipo de referencia) si la pasa sin una referencia (porque, como han dicho otros, está pasando una referencia al objeto en el montón y, por lo tanto, cambia la misma "memoria").

Sin embargo, no puede cambiar "list", "list" es una variable que apunta a un objeto de tipo List. Solo puede cambiar "lista" si lo pasa por referencia (para hacer que apunte a otro lugar). Obtiene una copia de la referencia, que si se modifica, solo se puede observar dentro de su método.


Solo los tipos primitivos como int, double, etc. pasan por valor.

Los tipos complejos (como la lista) se pasan por referencia (que es un puntero que pasa por valor, para ser exactos).


Una variable, parámetro o campo de tipo "Lista", o cualquier otro tipo de referencia, en realidad no contiene una lista (u objeto de ninguna otra clase). En cambio, tendrá algo así como "Object ID # 29115" (no como una cadena real, por supuesto, sino una combinación de bits, lo que significa esencialmente eso). En otro lugar, el sistema tendrá una colección indexada de objetos llamada el montón; si alguna variable del tipo List contiene "Object ID # 29115", entonces el objeto # 29115 en el montón será una instancia de List o algún tipo derivado de la misma.

Si MyFoo es una variable de tipo List, una declaración como ''MyFoo.Add ('' George '')'' en realidad no cambiará MyFoo; en su lugar, significa "Examinar el ID de objeto almacenado en MyFoo, e invocar el método" Agregar "del objeto almacenado en él. Si MyFoo sostuvo" Object ID # 19533 "antes de que se ejecute la instrucción, continuará haciéndolo después, pero Object ID # 19533 tendrá invocado su método Add (probablemente alterando ese objeto). Por el contrario, una declaración como "MyFoo = MyBar" hará que MyFoo mantenga el mismo ID de objeto como MyBar, pero en realidad no hará nada a los objetos en Pregunta: Si MyBar tenía "Object ID # 59212" antes de la declaración, entonces después de la declaración, MyFoo también tendrá "ObjectId # 59212". No habrá sucedido nada con el ID de objeto # 19533, ni con el ID de objeto # 59212.