Pregunta Lista aprobada por ref. Ayudame a explicar este comportamiento.


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 habría pasado por ref, y la salida

3
4

La lista es de hecho "aprobada por ref", pero solo el sort la función tiene efecto. La siguiente declaración myList = myList2; no tiene efecto.

Entonces la salida es de hecho:

10
50
100

¿Puedes ayudarme a explicar este comportamiento? Si de hecho myList no es pasado por ref (como aparece de myList = myList2 no tomando efecto), ¿cómo myList.Sort() ¿tomar efecto?

Estaba asumiendo incluso que esa declaración no surta efecto y que el resultado sea:

100
50
10

73
2017-11-30 06:49


origen


Respuestas:


Estás pasando un referencia a la lista, Pero tu no son pasando la variable de la lista por referencia - Entonces cuando llamas ChangeList el valor de la variable (es decir, la referencia - pensar "puntero") se copia - y cambia a valor del parámetro dentro ChangeList  no son visto por TestMethod.

tratar:

private void ChangeList(ref List<int> myList) {...}
...
ChangeList(ref myList);

Esto luego pasa una referencia a la variable local  myRef (como declarado en TestMethod); ahora, si reasigna el parámetro dentro ChangeList también estás reasignando la variable dentro  TestMethod.


86
2017-11-30 06:52



Inicialmente, se puede representar gráficamente de la siguiente manera:

Init states

Luego, se aplica el género myList.Sort(); Sort collection

Finalmente, cuando lo hiciste: myList' = myList2, perdiste el de la referencia pero no el original y la colección permaneció ordenada.

Lost reference

Si usa por referencia (ref) entonces myList' y myList se convertirá en lo mismo (solo una referencia).

Nota: yo uso myList' para representar el parámetro que usas en ChangeList (porque le dio el mismo nombre que el original)


154
2018-04-22 22:41



Aquí hay una manera fácil de entenderlo

  • Su lista es un objeto creado en el montón. La variable myList es un referencia a ese objeto

  • En C # nunca pasas objetos, pasas sus referencias por valor.

  • Cuando accede al objeto de la lista a través de la referencia aprobada en ChangeList (al ordenar, por ejemplo) se cambia la lista original.

  • La asignación en el ChangeList El método se basa en el valor de la referencia, por lo tanto, no se realizan cambios en la lista original (todavía en el montón pero no se hace referencia a la variable de método).


16
2017-11-30 07:13



esta El enlace le ayudará a entender el pase 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 el tipo de objeto de referencia usando la palabra clave ref, entonces podemos asignar otro objeto a la misma variable y eso cambia el objeto entero.


6
2017-11-30 07:00



C # solo hace una copia superficial cuando pasa por valor a menos que el objeto en cuestión se ejecute ICloneable (que aparentemente el Listclase no).

Lo que esto significa es que copia el List sí 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 original List.

Si cambia los valores de las cosas, su nuevo List referencias, cambias el original List también (ya que hace referencia a los mismos objetos). Sin embargo, luego cambia lo que myList referencias en su totalidad, a un nuevo List, y ahora solo el original List está haciendo referencia a esos enteros.

Leer el Pasar parámetros de tipo de referencia sección de este artículo de MSDN sobre "Pasar parámetros" para más información.

"Cómo puedo clonar una lista genérica en C #" de StackOverflow habla sobre cómo hacer una copia profunda de una lista.


4
2017-11-30 07:24



Aunque estoy de acuerdo con lo que todos han dicho anteriormente. Tengo una opinión diferente sobre 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 que pasa una variable de puntero por valor Cuando llama a ChangeList (myList) pasa el puntero a (Global) myList. Ahora esto está almacenado en la variable myList (local). Así que ahora su myList (local) y myList (global) apuntan a la misma lista. Ahora haces un género => funciona porque (local) myList hace referencia al myList (global) original A continuación, cree una nueva lista y asigne el puntero a su myList (local). Pero tan pronto como la función sale de la variable myList (local) se destruye. HTH

class Test
{
    List<int> myList = new List<int>();
    public void TestMethod()
    {

        myList.Add(100);
        myList.Add(50);
        myList.Add(10);

        ChangeList();

        foreach (int i in myList)
        {
            Console.WriteLine(i);
        }
    }

    private void ChangeList()
    {
        myList.Sort();

        List<int> myList2 = new List<int>();
        myList2.Add(3);
        myList2.Add(4);

        myList = myList2;
    }
}

3
2017-12-22 22:36



Utilizar el ref palabra clave.

Mira la referencia definitiva aquí para entender los parámetros que pasan
Para ser específico, mira esta, para comprender el comportamiento del código.

EDITAR: Sort funciona en la misma referencia (que se pasa por valor) y, por lo tanto, los valores se ordenan. Sin embargo, asignar una nueva instancia al parámetro no funcionará porque el parámetro se pasa por valor, a menos que pones ref.

Poniendo ref le permite cambiar el puntero a la referencia a una nueva instancia de List en tu caso. Sin ref, puede trabajar en el parámetro existente, pero no puede hacer que apunte a otra cosa.


2
2017-11-30 06:53