2011-03-11 16 views
7

Tengo la siguiente propiedad pública, que expone una Arraylist:Propiedades: por valor o referencia?

public ArrayList SpillageRiskDescriptions 
     { 
      get 
      { 
       return _SpillageRiskDescriptions; 
      } 
      set 
      { 
       _SpillageRiskDescriptions = value; 
      } 
     } 

otra parte estoy llamando

SpillageRiskDescriptions.Add("VENTILATE AREA"); 
SpillageRiskDescriptions.Add("DO NOT ALLOW SPILLAGE TO ENTER MAINS"); 

Estas parecen ser la adición de elementos a la ArrayList privada _SpillageRiskDescriptions (a través de la propiedad) mientras que esperaba que esto causara un problema. Por lo tanto, ¿estoy en lo cierto al pensar que las propiedades devuelven una referencia a la variable original y no la pasan por valor? ¿Esto es porque ArrayList es un tipo de referencia? ¿Ocurrirá lo mismo con un int (por ejemplo?)

Respuesta

9

Técnicamente siempre es por valor, pero debe comprender lo que se está transmitiendo. Como es un tipo de referencia, está pasando una referencia atrás (pero por valor).

Espero que tenga sentido. Siempre devuelve el resultado por valor, pero si el tipo es una referencia, está devolviendo la referencia por valor, lo que significa que puede cambiar el objeto, pero no a qué objeto se refiere.

+2

Piense en ello como C++, puede pasar un puntero a un objeto, y puede modificar a qué apunta ese puntero, pero no puede hacer que apunte a otra cosa porque tiene una copia del puntero y no del puntero original . Si desea cambiar a qué objeto apunta, debe pasar un puntero a un puntero (o una referencia a un puntero). Esta es la razón por la cual en C# necesita las palabras clave ref y out si quiere alterar a qué objeto se hace referencia. –

+0

Excelente: tiene perfecto sentido –

1

No tiene nada que ver con si se trata de una propiedad per se; es el tipo de datos de la propiedad. En este caso, está usando ArrayList, que es una clase que se pasa por referencia. Si la propiedad se escribiera como int, se aprobaría por valor.

2

C# devuelve objetos por referencia.

Sólo las cosas que no son devueltos por el valor son:

Los tipos primitivos.
tipos de estructura.
Enums.

+0

verdadero en esencia, aunque técnicamente devuelve referencias de objeto por valor. –

+0

También los punteros C++ se pasan por valor, pero esa es la definición de referencia. La dirección del objeto se pasa en lugar del objeto en sí. –

0

Una propiedad es en realidad un par de dos métodos: un colocador y un captador. Pasan el valor del campo de respaldo (o lo que sea que se use como fuente/destino) tal como es. Por lo tanto, para los tipos de referencia se pasa la referencia, y para los tipos de valor se pasa el valor.

// this is how the getter method looks like 
public ArrayList get_SpillageRiskDescriptions() 
{ 
    return _SpillageRiskDescriptions; 
} 

// this is how the setter method looks like 
public void set_SpillageRiskDescriptions(ArrayList value) 
{ 
    _SpillageRiskDescriptions = value; 
} 

Tenga en cuenta que mediante la asignación de una instancia ArrayList en su propiedad que, básicamente, reemplazar la instancia ArrayList a la que apunta el campo respaldo.

para responder a sus preguntas particulares:

Por lo tanto estoy en lo cierto al pensar que propiedades devuelven una referencia a la variable original y no pasar de largo valor?

No, utilizando el getter no obtiene una referencia al campo _SpillageRiskDescriptions. Obtiene el valor del campo que es una referencia a una instancia ArrayList (asignada dinámicamente).

Esto es porque ArrayList es un tipo de referencia?

Sí, ArrayList es un tipo de referencia y por lo tanto reciben la referencia a lo particular ArrayList ejemplo.

¿Ocurrirá lo mismo con un int (por ejemplo?)

Sí y no. , recibirá el valor de un campo int. Y no, int es un tipo de valor, por lo que si modifica el valor sin volverlo a establecer explícitamente, el campo subyacente no se verá afectado.

0

No tiene nada que ver con la propiedad.

En este caso, está pasando una referencia a la lista de matriz por valor.

Si haces algo como

 void AddSomethingToArrayList(ArrayList spillageRiskDescriptions){ 
      spillageRiskDescriptions.Add("Something"); 
     } 

continuación, se modificará la referencia a la lista de arreglo.

Si se va a hacer algo como

 void ReassignArrayList(ArrayList spillageRiskDescriptions){ 
      spillageRiskDescriptions = new ArrayList(); 
      spillageRiskDescriptions.Add("Something"); 
     } 

entonces la referencia original a la lista de arreglo no sería cambiado en absoluto.

Pero si tuviera que pasar la referencia por referencia, tales como en:

 void ReassignArrayListByRef(ref ArrayList spillageRiskDescriptions){ 
      spillageRiskDescriptions = new ArrayList(); 
      spillageRiskDescriptions.Add("Something"); 
     } 

entonces su propiedad sería terminar con una nueva lista de matriz con un solo elemento.

7

Las otras respuestas han respondido correctamente a su pregunta principal: que el valor de un propiedad de tipo de referencia es una referencia a un ejemplo del tipo de referencia.

La pregunta más importante es "¿ahora qué haces al respecto?" Presumiblemente usted hace no quiere código que puede obtener la lista para poder cambiar él.

Aquí hay varias opciones.

En primer lugar, haga lo que haga, le recomiendo que deje de usar ArrayList en este momento y empiece a usar un tipo más moderno y seguro para almacenar una lista de cosas. List<string> viene inmediatamente a la mente.

En segundo lugar, ¿es necesario que el setter de la propiedad sea público? ¿Quieres que cualquiera pueda cambiar esa lista? ¿O debería el tipo en sí mismo ser responsable de actualizarlo de alguna manera? Consideraría hacer el setter privado.

En tercer lugar, tenemos una sintaxis más compacta para una propiedad "trivial".Usted podría estar diciendo

public List<string> SpillageListDescriptions { get; private set; } 

y el compilador generará el campo de respaldo para usted.

Tenga en cuenta que List<string> aún permite la mutación.

Si todo lo que el cliente le importa es ser capaz de iterar sobre la lista de una cosa a la vez, entonces usted puede hacer esto:

private List<string> descriptions = whatever; 
public IEnumerable<string> SpillageListDescriptions 
{ 
    get 
    { 
     if (descriptions == null) yield break; 
     foreach(var description in descriptions) 
      yield return description; 
    } 
} 

y ahora es imposible para la persona que llama para mutar la lista, porque todo lo que les das es un iterador sobre él, no acceso a la lista en sí.

O usted podría hacer:

private List<string> descriptions = whatever; 
public IList<string> SpillageListDescriptions 
{ 
    get 
    { 
     return new ReadOnlyCollection<string>(descriptions); 
    } 
} 

Y ahora la persona que llama tiene una vista de sólo lectura de la lista que va a lanzar una excepción si intentan modificarlo.

+0

Muchas gracias por sus comentarios, sin embargo, la mayoría de estos (sintaxis corta de propiedad y setter privado con getter público) solo están disponibles en versiones posteriores del framework. Estoy usando .NET2. La razón por la que estoy visitando esto es para poder convertir ArrayList en la lista . Sin embargo, es bueno saber que lo que estoy haciendo es lo correcto. –

+0

La única solución que mencionó que no está disponible en .Net 2 es propiedades automáticas, que pueden implementarse trivialmente en .Net 2 a mano. También necesitarás reemplazar 'var' con' string'. – Brian

Cuestiones relacionadas