Pasar objetos por referencia o valor en C#

Resuelto Michael asked hace 12 años • 9 respuestas

En C#, siempre pensé que las variables no primitivas se pasaban por referencia y los valores primitivos se pasaban por valor.

Entonces, al pasar a un método cualquier objeto no primitivo, cualquier cosa que se haga al objeto en el método afectaría el objeto que se pasa. (C# 101 cosas)

Sin embargo, he notado que cuando paso un objeto System.Drawing.Image, este no parece ser el caso. Si paso un objeto system.drawing.image a otro método y cargo una imagen en ese objeto, luego dejo que ese método salga del alcance y vuelvo al método de llamada, ¿esa imagen no se carga en el objeto original?

¿Por qué es esto?

Michael avatar Jan 03 '12 13:01 Michael
Aceptado

Los objetos no se pasan en absoluto. De forma predeterminada, el argumento se evalúa y su valor se pasa, por valor, como valor inicial del parámetro del método que estás llamando. Ahora el punto importante es que el valor es una referencia para los tipos de referencia: una forma de llegar a un objeto (o nulo). Los cambios en ese objeto serán visibles para la persona que llama. Sin embargo, cambiar el valor del parámetro para hacer referencia a un objeto diferente no será visible cuando utilice pasar por valor, que es el valor predeterminado para todos los tipos.

Si desea utilizar el paso por referencia, debe utilizar o out, refya sea que el tipo de parámetro sea un tipo de valor o un tipo de referencia. En ese caso, efectivamente, la variable en sí se pasa por referencia, por lo que el parámetro usa la misma ubicación de almacenamiento que el argumento, y la persona que llama ve los cambios en el parámetro en sí.

Entonces:

public void Foo(Image image)
{
    // This change won't be seen by the caller: it's changing the value
    // of the parameter.
    image = Image.FromStream(...);
}

public void Foo(ref Image image)
{
    // This change *will* be seen by the caller: it's changing the value
    // of the parameter, but we're using pass by reference
    image = Image.FromStream(...);
}

public void Foo(Image image)
{
    // This change *will* be seen by the caller: it's changing the data
    // within the object that the parameter value refers to.
    image.RotateFlip(...);
}

Tengo un artículo que entra en muchos más detalles sobre esto . Básicamente, "pasar por referencia" no significa lo que usted cree que significa.

Jon Skeet avatar Jan 03 '2012 06:01 Jon Skeet

Se habían agregado muchas buenas respuestas. Todavía quiero contribuir, tal vez se aclare un poco más.

Cuando pasa una instancia como argumento al método, pasa el valor copyde la instancia. Ahora, si la instancia que pasas es value type(reside en stack), pasas la copia de ese valor, por lo que si lo modificas, no se reflejará en la persona que llama. Si la instancia es un tipo de referencia, pasa la copia de la referencia (nuevamente reside en stack) al objeto. Entonces tienes dos referencias al mismo objeto. Ambos pueden modificar el objeto. Pero si dentro del cuerpo del método crea una instancia de un nuevo objeto, su copia de la referencia ya no hará referencia al objeto original, sino que se referirá al nuevo objeto que acaba de crear. Entonces terminarás teniendo 2 referencias y 2 objetos.

OlegI avatar Nov 28 '2019 21:11 OlegI