2010-02-24 13 views
6

Pasar Value Type parámetros a las funciones en C# es por valor a menos que use la palabra clave ref o out en el parámetro. ¿Pero esto también se aplica al Reference Types?¿Se pasa ILists por valor?

Específicamente tengo una función que toma un IList<Foo>. ¿La lista transferida a mi función será una copia de la lista con una copia de sus objetos contenidos? ¿O las modificaciones a la lista también se aplicarán a la persona que llama? Si es así, ¿hay alguna manera inteligente de pasar una copia?

public void SomeFunction() 
{ 
    IList<Foo> list = new List<Foo>(); 
    list.Add(new Foo()); 
    DoSomethingWithCopyOfTheList(list); 
    .. 
} 

public void DoSomethingWithCopyOfTheList(IList<Foo> list) 
{ 
    // Do something 
} 
+0

¡Gracias por las respuestas rápidas, amigos! Fue como esperaba Acabo de tener un momento de incertidumbre allí. – stiank81

+0

Si quisiera hacer algo inteligente, podría hacer una lista de su propia clase, que implícitamente se envía a IList haciendo una copia. El único beneficio que puedo ver de esto es que teóricamente impide que "olvides" hacer una copia cuando pasas por una colección. – kyoryu

+0

No, no quiero hacer eso ... El constructor List que toma IEnumerable parece ser tan inteligente como puede ser. Todo lo que necesito .. – stiank81

Respuesta

16

Todos los parámetros se pasan por valor a menos que utilice explícitamente ref o out. Sin embargo, cuando pasa una instancia de un tipo de referencia, pasa la referencia por valor. Es decir. la referencia en sí misma se copia, pero dado que todavía apunta a la misma instancia, puede modificar la instancia a través de esta referencia. Es decir. la instancia no se copia La referencia es

Si desea hacer una copia de la lista en sí, List<T> tiene un handy constructor, que toma un IEnumerable<T>.

+1

Además, si cambia la referencia dentro del cuerpo de la función, este cambio no será visible en la persona que llama. +1 de mi parte –

+1

@Aggelos: Exactamente. Esa es una propiedad de pasar por valor. –

3

La lista se pasa por referencia, por lo que si se modifica la lista de algunaFuncion, que modifica la lista de la persona que llama así.

Se puede crear una copia de una lista mediante la creación de una nueva:

var newList = new List<Foo>(oldList); 
2

su lista se aprobó mediante referencia. Si desea pasar una copia de la lista que puede hacer:

IList<Foo> clone = new List<Foo>(list); 

si se agrega/eliminar elementos en el clon no va a modificar la lista pero las modificaciones de los propios elementos se tendrán en cuenta en tanto liza.

+0

+1 para la explicación: '... pero las modificaciones de los elementos mismos se tendrán en cuenta en ambas listas. –

1

Cuando pasa el tipo de referencia por valor (sin las palabras clave ref o fuera), puede modificar este tipo de referencia dentro de este método y todos los cambios se reflejarán en el código de las personas que llaman.

para resolver su problema que puede crear explícitamente una copia y pasar esta copia a su función, o puede utilizar:

list.AsReadOnly(); 
0

Al pasar los tipos de referencia, se pasa a la referencia. Este es un concepto importante.

Si pasa una referencia

byref, se pasa el referencia (puntero) directamente.

byval, usted pasa una copia de la referencia (puntero).

Una referencia no es la instancia a la que se hace referencia. Una referencia es análoga a un puntero.

Para pasar una copia de la instancia de un tipo de referencia, primero debe hacer una copia y pasar una referencia a la copia. Como tal, no modificarás la instancia original.

+2

Dudo que lo haya puesto de una manera más confusa. – Blindy

+0

¿es eso mejor? – MaLio

10

No estás solo; esto confunde a mucha gente.

Así es como me gusta pensar en ello.

Una variable es una ubicación de almacenamiento.

Una variable puede almacenar algo de un tipo particular.

Existen dos tipos de tipos: tipos de valores y tipos de referencia.

El valor de una variable de tipo de referencia es una referencia a un objeto de ese tipo.

El valor de una variable de tipo de valor es un objeto de ese tipo.

Un parámetro formal es un tipo de variable.

Existen tres tipos de parámetros formales: parámetros de valor, parámetros de ref y parámetros de salida.

Cuando utiliza una variable como argumento correspondiente a un parámetro de valor, el valor de la variable se copia en el almacenamiento asociado con el parámetro formal. Si la variable es de tipo de valor, se realiza una copia del valor. Si la variable es de tipo de referencia, se hace una copia de la referencia, y las dos variables ahora se refieren al mismo objeto. De cualquier manera, se realiza una copia del valor de la variable.

Cuando utiliza una variable como argumento correspondiente a un parámetro out o ref , el parámetro se convierte en un alias para la variable. Cuando uno dice:

void M(ref int x) { ...} 
... 
int y = 123; 
M(ref y); 

lo que está diciendo es "X e Y son ahora la misma variable". Ambos se refieren a la misma ubicación de almacenamiento.

Me parece mucho más fácil de comprender que pensar en cómo se implementa realmente el alias, pasando la dirección administrada de la variable al parámetro formal.

¿Está claro?

+0

Super claro! Gracias :-) – stiank81

Cuestiones relacionadas