2010-02-19 8 views
8

Cuando la propiedad tienen algún tipo de colección comoPropiedades de la colección Tipo de

public IList<MyItemClass> MyList{ get; } 

en mi humilde opinión, es mejor volver colección vacía en lugar de valor nulo.
Hay muchas formas de implementar dicha funcionalidad.

public IList<MyItemClass> MyList{ get; private set; } 
public MyClass(){ 
    MyList = new List<MyItemClass>(); 
} 

De esta manera, permite disminuir el número de campos de clase, pero debe poner el código en cada constructor.

private List<MyItemClass> _myList = new List<MyItemClass>(); 
public IList<MyItemClass> MyList{ get{ return _myList; } } 

Esta es la manera estándar. Pero cuando alguien escribe algo en tu código, puede usar el campo privado en lugar de la propiedad y puedes obtener algunos errores cuando realizas la acción de refactorización.

private List<MyItemClass> _myList; 
public IList<MyItemClass> MyList{ get{ return _myList??(_myList = new List<MyItemClass>()); } } 

Y esta es la variante de la manera anterior con carga diferida.

¿Qué prefiere devolver como valor predeterminado para la recopilación? Si esto es colección vacía, ¿cómo lo implementas?

Respuesta

2

Desde el .NET Design Guidelines:

sí proporcionan valores por defecto para todas las propiedades sensibles, asegurando que los valores por defecto no dan lugar a un agujero de seguridad o un diseño extremadamente ineficiente.

La extensión de este principio y combinándolo con el Principle of Least Surprise debe dejar bien claro que se debe siempre devuelven una colección vacía en lugar de null.

¿Por qué poner la carga de verificar nulo en su interlocutor cuando puede proporcionar un valor predeterminado sensible e intuitivo?

El punto de encapsulación es para hacer el trabajo en un solo lugar. Puede hacer que la implementación de clase específica sea un poco más compleja, pero simplifica el uso de su API.

En la mayoría de los casos implemento la colección como un invariante en el tipo que contiene:

public class MyClass 
{ 
    private readonly List<Foo> foos; 

    public class MyClass() 
    { 
     this.foos = new List<Foo>(); 
    } 
} 

Aviso el uso de la palabra clave readonly que asegura que una vez establecido, la lista no se puede reemplazar o anulada (pero aún puede ser reiniciado). Esto protege la lista como una invariante de la clase, lo que me evita escribir cheques nulos en el resto de mi código.

La carga lenta también es una expresión de codificación válida, pero solo la uso cuando la necesito explícitamente.

0

Opción 2 (forma estándar) y evite el problema de la refactorización asegurándose de que las pruebas de su unidad verifiquen que la lista vacía se devuelva cuando lo espere.

0

Prefiero la segunda variante porque es más obvia y disminuyo el tamaño del constructor. Pero por lo general se hacen de este campo de sólo lectura:

private readonly List<MyItemClass> _myList = new List<MyItemClass>(); 
1

Volviendo null no es precisamente ideal. Para alternativas; depende del uso. OMI, esta versión (copiado del poste principal) es el más simple todavía qué todo lo que necesita:

private List<MyItemClass> _myList = new List<MyItemClass>(); 
public IList<MyItemClass> MyList { get { return _myList; } } 

y como una ventaja, que va a trabajar con XmlSerializer, donde, como cualquier cosa con un private setno lo hará funciona (un error; ve al colocador pero no se da cuenta de que no puede usarlo).

El enfoque perezoso suele ser OMI excesivo, ya que en la mayoría de los casos interesantes van a llenar las listas de todos modos.

1

Normalmente utilizo la variante donde inicializa la lista en el constructor. Esto podría hacer que el constructor esté más "hinchado", pero la responsabilidad de los constructores es construir el objeto. La configuración de buenos valores predeterminados es en mi humilde opinión completamente dentro de sus responsabilidades. Además, como bonificación, no tiene que preocuparse por los campos privados, lo que hace que el código se vea más limpio.

Claro, la refactorización obtiene poco más difícil, pero no significativamente. No olvide que puede encadenar sus constructores (la mayor parte del tiempo de todos modos), por lo que incluso si tiene varios constructores, solo podrá tener que escribir el código del inicializador una vez.

No olvide documentar que el valor predeterminado es una colección vacía. Y establecer el campo de recopilación de solo lectura es una buena práctica a menos que tenga una buena razón para reiniciarlo más tarde.

Cuestiones relacionadas