Eche un vistazo al siguiente programa:
class Test
{
List<int> myList = new List<int>();
public void TestMethod()
{
myList.Add(100);
myList.Add(50);
myList.Add(10);
ChangeList(myList);
foreach (int i in myList)
{
Console.WriteLine(i);
}
}
private void ChangeList(List<int> myList)
{
myList.Sort();
List<int> myList2 = new List<int>();
myList2.Add(3);
myList2.Add(4);
myList = myList2;
}
}
Supuse myList
que habría pasado ref
, y la salida sería
3
4
De hecho, la lista se "pasa por ref", pero solo la sort
función tiene efecto. La siguiente declaración myList = myList2;
no tiene ningún efecto.
Entonces la salida es de hecho:
10
50
100
¿Puedes ayudarme a explicar este comportamiento? Si de hecho myList
no se pasa por referencia (como parece por myList = myList2
no tener efecto), ¿cómo entra myList.Sort()
en vigor?
Estaba asumiendo que incluso esa declaración no surtiría efecto y que el resultado sería:
100
50
10
c#
list
pass-by-reference
nmdr
fuente
fuente
ChangeList
devolver un enList<int>
lugar de unvoid
si de hecho se está creando una nueva lista.Respuestas:
Está pasando una referencia a la lista , pero no está pasando la variable de lista por referencia , por lo que cuando llama
ChangeList
al valor de la variable (es decir, la referencia, piense que se copia "puntero"), y cambia el valor de la el parámetro dentroChangeList
no es visto porTestMethod
.tratar:
Esto luego pasa una referencia a la variable local
myRef
(como se declara enTestMethod
); ahora, si reasigna el parámetro dentroChangeList
, también está reasignando la variable dentroTestMethod
.fuente
ChangeList
, solo se copia la referencia : es el mismo objeto. Si cambia el objeto de alguna manera, todo lo que tenga una referencia a ese objeto verá el cambio.Inicialmente, se puede representar gráficamente de la siguiente manera:
Luego, se aplica la ordenación
myList.Sort();
Finalmente, cuando lo hizo:,
myList' = myList2
perdió el de la referencia pero no el original y la colección quedó ordenada.Si usa por referencia (
ref
), entoncesmyList'
ymyList
se convertirá en el mismo (solo una referencia).Nota: utilizo
myList'
para representar el parámetro que usa enChangeList
(porque le dio el mismo nombre que el original)fuente
Aquí tienes una forma fácil de entenderlo.
Su lista es un objeto creado en montón. La variable
myList
es una referencia a ese objeto.En C # nunca pasa objetos, pasa sus referencias por valor.
Cuando accede al objeto de lista a través de la referencia pasada en
ChangeList
(mientras ordena, por ejemplo), la lista original cambia.La asignación en el
ChangeList
método se realiza al valor de la referencia, por lo tanto, no se realizan cambios en la lista original (todavía en el montón pero ya no se hace referencia a la variable del método).fuente
Este enlace lo ayudará a comprender el paso por referencia en C #. Básicamente, cuando un objeto de tipo de referencia se pasa por valor a un método, solo los métodos que están disponibles en ese objeto pueden modificar el contenido del objeto.
Por ejemplo, el método List.sort () cambia el contenido de la lista, pero si asigna algún otro objeto a la misma variable, esa asignación es local para ese método. Es por eso que myList permanece sin cambios.
Si pasamos un objeto de tipo de referencia usando la palabra clave ref, entonces podemos asignar algún otro objeto a la misma variable y eso cambia todo el objeto en sí.
(Editar: esta es la versión actualizada de la documentación vinculada anteriormente).
fuente
C # solo hace una copia superficial cuando pasa por valor a menos que el objeto en cuestión se ejecute
ICloneable
(lo que aparentemente laList
clase no lo hace).Lo que esto significa es que copia el
List
mismo, pero las referencias a los objetos dentro de la lista siguen siendo las mismas; es decir, los punteros continúan haciendo referencia a los mismos objetos que el originalList
.Si cambia los valores de las cosas que sus nuevas
List
referencias, también cambia el originalList
(ya que hace referencia a los mismos objetos). Sin embargo, luego cambia lasmyList
referencias por completo a una nuevaList
, y ahora solo la originalList
hace referencia a esos números enteros.Lea la sección Pasando parámetros de tipo de referencia de este artículo de MSDN sobre "Pasando parámetros" para obtener más información.
"¿Cómo clono una lista genérica en C #" de StackOverflow habla sobre cómo hacer una copia profunda de una lista.
fuente
Si bien estoy de acuerdo con lo que todos han dicho anteriormente. Tengo una visión diferente de este código. Básicamente, está asignando la nueva lista a la variable local myList, no a la global. si cambia la firma de ChangeList (List myList) a Private void ChangeList () verá el resultado de 3, 4.
Aquí está mi razonamiento ... Aunque la lista se pasa por referencia, piense en ello como pasar una variable de puntero por valor. Cuando llama a ChangeList (myList), está pasando el puntero a (Global) myList. Ahora esto se almacena en la variable myList (local). Así que ahora su myList (local) y myList (global) apuntan a la misma lista. Ahora haces una ordenación => funciona porque (local) myList hace referencia a la myList original (global). A continuación, crea una nueva lista y asigna el puntero a esa myList (local). Pero tan pronto como la función sale, la variable myList (local) se destruye. HTH
fuente
Utilice la
ref
palabra clave.Mire la referencia definitiva aquí para comprender los parámetros de paso.
Para ser específico, mire esto , para comprender el comportamiento del código.
EDITAR:
Sort
funciona sobre la misma referencia (que se pasa por valor) y, por lo tanto, los valores están ordenados. Sin embargo, asignar una nueva instancia al parámetro no funcionará porque el parámetro se pasa por valor, a menos que pongaref
.Poner le
ref
permite cambiar el puntero a la referencia a una nueva instancia deList
en su caso. Sinref
, puede trabajar en el parámetro existente, pero no puede hacer que apunte a otra cosa.fuente
Hay dos partes de memoria asignadas para un objeto de tipo de referencia. Uno en pila y otro en montón. La parte en la pila (también conocida como puntero) contiene una referencia a la parte en la pila, donde se almacenan los valores reales.
Cuando no se usa la palabra clave ref, solo se crea una copia de la parte en la pila y se pasa al método: referencia a la misma parte en el montón. Por lo tanto, si cambia algo en la parte del montón, esos cambios se mantendrán. Si cambia el puntero copiado, asignándolo para que haga referencia a otro lugar en el montón, no afectará al puntero de origen fuera del método.
fuente