2010-02-01 12 views
24

Ho una classe che mantiene un elenco di oggetti di un'altra classe. L'elenco di oggetti è una proprietà pubblica. Vorrei impedire agli utenti di aggiungere e rimuovere oggetti direttamente per elencare in questo modo:Esiste un'interfaccia di raccolta .NET che impedisce l'aggiunta di oggetti?

 MyObject.MyListProperty.Add(object); 

Invece voglio loro di utilizzare metodo che internamente fare un po 'di elaborazione e quindi aggiungere oggetti alla lista.

Ho alcune idee:

  • creare discendente di List<T> e override di aggiungere e rimuovere
  • ritorno nuova copia di lista attraverso la proprietà getter (lista è relativamente breve, non più di 30 oggetti)

C'è qualche interfaccia di raccolta che non ha Aggiungi e rimuovi?

Edit:
ho intenzione di andare con ReadOnlyCollection<T>. Il motivo è che la raccolta incartata può essere aggiornata e le modifiche saranno immediatamente visibili nell'oggetto di sola lettura (vedere Esempi di codice MSDN per ReadOnlyCollection<T> e AsReadOnly()). Ciò consente di creare una lista di sola lettura una sola volta.

Il problema con IEnumerable è che l'oggetto può essere reindirizzato all'originale List<T> e quindi direttamente manipolato.

+0

Sono stato anche alla ricerca di questo +1 – Ravisha

risposta

36

È possibile utilizzare ReadOnlyCollection - avvolgere la raccolta in questo e restituire il ReadOnlyCollection agli utenti della vostra classe:

return new ReadOnlyCollection(innerCollection); 

sia utilizzando il metodo della classe List<T>AsReadOnly:

return innerCollection.AsReadOnly(); 

Il IEnumerable l'interfaccia farà ciò di cui hai bisogno, in quanto ha un solo membro GetEnumerator(), che ti permetterà solo di scorrere gli oggetti.

+2

AsReadOnly (http://msdn.microsoft.com/en-us/library/e78dcd75. aspx) non è Linq –

+0

Grazie per la correzione - risolto! – Oded

+0

'IReadOnlyCollection ' e 'AsReadOnly' accetta solo' IList '. Esiste anche una soluzione per "ICollection "? – Shimmy

0

Si potrebbe semplicemente dare loro un oggetto che restituisce sempre un enumeratore che possono utilizzare per accedere alla struttura?

5

Forse il metodo AsReadOnly farà il trucco, per consegnare un'istanza di sola lettura al pubblico.

In caso contrario, IEnumerable<T> non ha AddRemove, in modo da poter fare qualcosa di simile:

private List<int> _myList; 
public IEnumerable<int> MyList 
{ 
    get 
    { 
     return this._myList.ToList(); 
    } 
} 

avrei preferito andare per il IEnumerable<T> (+ copia) come per ReadOnlyCollection<T>, perché: modifiche alla lista di base (da cui viene creata la tua raccolta di sola lettura da) verrà immediatamente visualizzata nella tua istanza della raccolta di sola lettura. questo potrebbe causare problemi di blocco e straordina :)

+0

perché restituire this._myList.ToList(); 'e non' return this._myList; ' –

+0

E a proposito di' IList 'e' ToArray'? Il meglio di entrambi i mondi, no? –

+0

IList ha un metodo Add, quindi l'elenco non dovrebbe essere di sola lettura e puoi modificare il contenuto di un array (non che ciò influirebbe su questa classe poiché l'array è una copia). L'unica interfaccia che risolve il problema dell'OP è IEnumerable –

5

La soluzione più semplice sarebbe quella di esporre la vostra lista come una delle seguenti IEnumerable, ICollectionReadOnlyCollection tramite una proprietà pubblica.

Quindi è possibile creare il proprio type di elenco che espone il vostro Items come uno dei precedenti, ma ha un metodo interno per l'aggiunta per es.

public class MyList<MyType> 
{ 
    private List<MyType> items; 

    public MyList() 
    { 
     items = new List<MyType>(); 
    } 

    public IEnumerable Items { get { return items.AsEnumerable(); } } 
    public Add(MyType item) 
    { 
     // do internal processing 
     items.Add(item); 
    } 
} 
+0

Raffreddare +1 per la spiegazione – Ravisha

+3

Si noti che ciò non impedisce la trasmissione della raccolta alla Lista e la chiamata Aggiungi su di essa. ReadOnlyCollection è la strada da percorrere se hai davvero bisogno di evitare Add. Inoltre, non è necessario chiamare gli elementi.AsEnumerable e non penso che questo verrà compilato come scritto perché AsEnumerable() restituirà IEnumerable e Items è digitato come IEnumerable. –

+0

@Jamie 'IEnumerable ' eredita da 'IEnumerable', quindi verrà compilato, ma sono d'accordo che restituiscano IEnumerable e che AsEnumerable sia ridondante. –

2

Fuori dalla scatola, solo IEnumerable<T> fornirà questo senza esporre alcun Add e Remove metodi pubblici che potrebbero ingannare il cliente in ricevendo un'eccezione di runtime.

Se si desidera che l'API pubblica dichiari esplicitamente che la raccolta è di sola lettura e che è necessario un indicizzatore, è necessario scrivere il proprio wrapper attorno a List<T> o T[] esistente.

+0

'IEnumerable ' non supporta l'accesso casuale sebbene –

0

ICollection (la versione non generica) ha ottenuto solo IEnumerable + Count

Problemi correlati