2010-12-09 28 views
5

Al implementar una incubadora para una propiedad de la lista (en C#) es una mala cosa es escribir es como:Lista de propiedades Setter

private List<string> _TheList = new List<string>(); 
    public List<string> TheList 
    { 
     get { return _TheList; } 
     set { _TheList = value; } 
    } 

En caso de que no se puede escribir como:

private List<string> _TheList = new List<string>(); 
    public List<string> TheList 
    { 
     get { return _TheList; } 
     set { _TheList = new List<string>(value); } 
    } 

Hasta hasta hoy he usado típicamente el primero, pero recientemente encontré un código que usaba el último y parecía que esta es probablemente la forma correcta de implementar esto.

No utilizará el anterior causa que la propiedad TheList se modifique cuando se realicen cambios en la lista externa que se le asigna. Por ejemplo:

List<string> list = new List<string>(); 
list.Add("Hello"); 

var c = new someClass(); 
c.TheList = list; 

Usando el antiguo será el siguiente código no romper la encapsulación de theList:

list.Clear(); 

Ahora c.TheList también está vacía, que puede no ser lo que queríamos. Sin embargo, utilizando el último enfoque, c.TheList no se borrará.

+0

No, la segunda solución no es correcta. Utilice la primera solución y si desea establecer una copia en lugar de una referencia, escriba c.TheList = new List (list); – vorrtex

+1

Eso depende de la semántica de tu propiedad. Es posible que algunas personas que llaman puedan configurar la lista y aún actualizarla "desde afuera". Cualquiera que sea el camino que tome, asegúrese de documentarlo adecuadamente. –

+0

Gracias por todas las excelentes respuestas. Me alegro de no haber empezado a utilizar el segundo enfoque sin antes verificarlo. Parece que el consenso es no proporcionar un colocador (en la mayoría de los casos) o, al menos, protegerlo. – mikesigs

Respuesta

7

Collection properties should be readonly.

Your property should expose a Collection<T>, not a List<T>.

EDITAR: Explicaciones:

Si otras copias del código de una referencia a la lista (por ejemplo, var list = Thingy.TheList), se puede llegar en mal estado, si se establece la propiedad a una lista diferente. (Terminará reteniendo a un huérfano)
En general, existen muy pocas razones para permitir que las personas hagan una propiedad apuntando a una instancia de colección diferente.

El uso de Collection<T> en lugar de le permite interceptar cambios en la colección y agregar validación o mantener los campos principales. (heredando Collection<T> y anulando InsertItem y otros métodos) Incluso puede agregar dicha lógica después de enviar una biblioteca sin romper el código de llamada.

+2

O exponer como 'ReadOnlyCollection ', 'List ' tiene un método AsReadOnly() para facilitar el retorno. – pstrjds

+0

¿Conoce algún buen artículo que explique por qué esos dos principios son ciertos? No veo completamente lo que está mal con tener una lista escribible como una propiedad. – JeremyWeir

+0

@jayrdub: Aquí tienes. – SLaks

3

Depende completamente de cómo desee que funcione su propiedad. Si quieres una copia, haz una copia. De lo contrario, no. A menudo, las propiedades de este tipo no exponen a un colocador, ya que reemplazar la lista completa no es una acción deseada para ese caso.

Por supuesto, utilizar su segundo método es potencialmente un riesgo de rendimiento, ya que la sintaxis de la propiedad oculta el hecho de que está copiando por completo y creando una nueva lista cada vez que utiliza el colocador.

0

En primer lugar, ambos son algo incorrectos. Las propiedades públicas realmente deberían estar expuestas como IList ya que List es específico de la implementación (fxcop en realidad lo advertirá cuando use List como propiedad pública).

En segundo lugar, si es posible, quisiera que el colocador sea privado. Usando el getter, un usuario puede agregar/eliminar/borrar/etc. pero simplifica los problemas que planteaste en tu pregunta.

+0

Normalmente usaré IList, pero dado que en el segundo enfoque estamos usando explícitamente una nueva Lista(), pensé que tenía más sentido definir la propiedad como tal. – mikesigs

+0

Me acabo de dar cuenta de que IList no incluye el método AddRange, que yo quiero. Solo la implementación de la Lista contiene este método. Entonces, ¿por qué no exponer esta propiedad como una lista . – mikesigs

6

Creo que como una lista es un objeto de referencia, todo lo que necesita hacer es obtener la referencia.Por lo tanto:

private List<string> _TheList = new List<string>(); 
public List<string> TheList 
{ 
    get { return _TheList; } 
} 

Una vez que tenga la referencia, y realizar cambios en la colección, que está cambiando _TheList

0

No creo que hay una respuesta universal a su pregunta. El comportamiento que describes puede o no ser lo que quieres.

En general estoy de acuerdo con SLaks que es más limpio para mantener las propiedades colecciones de sólo lectura, pero todo depende

0

No estoy seguro de haber entendido correctamente. Pero lo estoy haciendo así:

c.TheList = list.ToArray().ToList(); 
+1

¿Tienes una lista que convertir a una matriz y luego volver a una lista? Como muchos comentadores ya han acordado, normalmente no desea exponer la lista a través de un colocador, lo que debería hacer para hacer lo que ha propuesto. ¿Puedes explicar más lo que estás proponiendo aquí? – mikesigs

Cuestiones relacionadas