2010-02-19 14 views
8

Quando la proprietà hanno qualche tipo di raccolta comeproprietà di raccolta tipo

public IList<MyItemClass> MyList{ get; } 

IMHO, è meglio tornare insieme vuoto invece di valore nullo.
Esistono molti modi per implementare tale funzionalità.

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

In questo modo è possibile ridurre il numero di campi di classe, ma è necessario inserire il codice in ogni costruttore.

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

Questo è il modo standard. Ma quando qualcuno scrive qualcosa al tuo codice, può usare il campo privato invece della proprietà e puoi ottenere alcuni bug quando ti rifatti l'azione.

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

E questa è la variante del modo precedente con caricamento lazy.

Cosa si preferisce restituire come valore predefinito per la raccolta? Se questa è raccolta vuota, come la implementa?

risposta

2

Dal .NET Design Guidelines:

forniscono valori di default ragionevoli per tutte le proprietà, assicurando che le impostazioni predefinite non comportino un buco di sicurezza o di un design estremamente inefficiente.

allungabile questo principio e combinandola con il Principle of Least Surprise dovrebbe rendere chiaro che si dovrebbe restituire sempre un insieme vuoto invece di null.

Perché mettere l'onere della verifica di null sul chiamante quando è possibile fornire un valore predefinito ragionevole e intuitivo?

Il punto centrale di incapsulamento è quello di fare il lavoro in un unico luogo. Può rendere questa implementazione di classe specifica un po 'più complessa, ma rende più semplice l'utilizzo della sua API.

Nella maggior parte dei casi a implementare la collezione come un invariante nel tipo contenente:

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

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

Avviso l'uso della parola chiave readonly che assicura che, una volta impostata, la lista non può essere mai sostituire o reso nullo fuori (ma può ancora essere resettato). Questo protegge l'elenco come un invariante della classe, che mi impedisce di scrivere assegni nulli nel resto del mio codice.

Il caricamento lento è anche un valido idioma di codifica, ma lo uso solo quando ne ho bisogno esplicitamente.

0

Opzione 2 (modo standard) ed evitare il problema di refactoring verificando che l'elenco vuoto venga restituito quando previsto.

0

Preferisco la seconda variante perché è più ovvia e diminuisce la dimensione del costruttore. ma di solito è rendere questi campi di sola lettura:

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

Tornando null non è davvero l'ideale. Per alternative; dipende dall'uso. IMO, questa versione (copiato dalla posta centrale) è il più semplice ma fa tutto quello che serve:

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

e come un vantaggio, funzionerà con XmlSerializer, dove, come qualsiasi cosa con un private setnon lo farà funziona (un bug, vede il setter ma non si accorge che non può usarlo).

L'approccio pigro è solitamente eccessivo, come nella maggior parte dei casi in cui si inseriscono comunque gli elenchi.

1

Di solito utilizzo la variante in cui si inizializza l'elenco nel costruttore. Ciò potrebbe rendere il costruttore più "gonfio", ma la responsabilità del costruttore è che costruisce l'oggetto. L'impostazione di buoni valori predefiniti IMHO rientra completamente nelle sue responsabilità. Inoltre, come bonus, non devi preoccuparti dei campi privati, il che rende il codice più pulito.

Certo, il refactoring ha un piccolo più difficile, ma non significativo. Non dimenticare che puoi concatenare i costruttori (il più delle volte comunque), quindi anche se hai diversi costruttori dovresti essere in grado di scrivere il codice inizializzatore solo una volta.

Non dimenticare di documentare che il valore predefinito è una raccolta vuota. E l'impostazione del campo di raccolta in sola lettura è una buona pratica a meno che non si abbia una buona ragione per reimpostarla in un secondo momento.

Problemi correlati