Domanda

Ogni volta che creo un oggetto che ha una collezione di proprietà di andare avanti e indietro il modo migliore per farlo?

  1. di proprietà pubblica, con un getter che restituisce un riferimento alla variabile privata
  2. esplicito get_ObjList e set_ObjList i metodi che restituiscono e creare nuovi o clonato oggetti di ogni tempo
  3. esplicito get_ObjList che restituisce un IEnumerator e un set_ObjList che prende IEnumerator

Fa differenza se la raccolta è una matrice (cioè, objList.Clone()) versus un Elenco?

Se la restituzione di effettiva raccolta come riferimento è così male, perché crea dipendenze, allora perché tornare qualsiasi proprietà come riferimento?In qualsiasi momento si espone un bambino oggetto come riferimento le parti interne del bambino, che può essere modificato senza il padre "sapere" se il bambino ha una struttura cambiato evento.C'è un rischio di perdite di memoria?

E, non le opzioni 2 e 3 break di serializzazione?Questa è una cattura 22 o devo implementare la serializzazione personalizzata in qualsiasi momento avete una collezione di proprietà?

Generico ReadOnlyCollection sembra un buon compromesso per un uso generale.Si avvolge un IList e ne limita l'accesso.Forse questo aiuta con perdite di memoria e di serializzazione.Tuttavia ha ancora enumerazione preoccupazioni

Forse dipende solo.Se non si cura che la collezione è modificato, quindi basta esporla come accessor pubblico oltre a una variabile privata al #1.Se non vuoi che altri programmi per modificare la raccolta #2 e #3 è meglio.

Implicita nella domanda è perché il metodo rispetto ad un altro e quali sono le conseguenze sulla sicurezza, la memoria, la serializzazione, etc.?

È stato utile?

Soluzione

Come si espone una collezione dipende esclusivamente da come gli utenti devono poter interagire con esso.

1) Se gli utenti di aggiungere e rimuovere elementi da un oggetto della collezione, quindi un semplice di sola proprietà della raccolta è il migliore (opzione #1 dalla domanda originale):

private readonly Collection<T> myCollection_ = new ...;
public Collection<T> MyCollection {
  get { return this.myCollection_; }
}

Questa strategia è utilizzata per la Items collezioni in WindowsForms e WPF ItemsControl di controllo, in cui agli utenti di aggiungere e rimuovere elementi che si desidera che il controllo di visualizzazione.Questi controlli di pubblicare l'effettiva raccolta e l'uso di callback o listener di eventi per tenere traccia degli elementi.

WPF espone anche alcuni impostabile collezioni per consentire agli utenti di visualizzare un insieme di elementi che consentono di controllare, come il ItemsSource proprietà ItemsControl (opzione #3 dalla domanda originale).Tuttavia, questo non è un caso d'uso comune.


2) Se sarà solo leggere i dati gestiti dall'oggetto, quindi è possibile utilizzare un readonly collezione, come Quibblesome suggerito:

private readonly List<T> myPrivateCollection_ = new ...;
private ReadOnlyCollection<T> myPrivateCollectionView_;
public ReadOnlyCollection<T> MyCollection {
  get {
    if( this.myPrivateCollectionView_ == null ) { /* lazily initialize view */ }
    return this.myPrivateCollectionView_;
  }
}

Nota che ReadOnlyCollection<T> fornisce una visione in tempo reale di raccolta sottostante, quindi è necessario creare la vista una volta.

Se la raccolta interna non implementare IList<T>, oppure se si desidera limitare l'accesso per gli utenti più avanzati, invece, è possibile avvolgere l'accesso alla collezione attraverso un enumeratore:

public IEnumerable<T> MyCollection {
  get {
    foreach( T item in this.myPrivateCollection_ )
      yield return item;
  }
}

Questo approccio è semplice da implementare e fornisce anche l'accesso a tutti i soci senza esporre la raccolta interna.Tuttavia, esso richiede che la raccolta rimanere unmodfied, come BCL classi di raccolta genererà un'eccezione se si tenta di enumerare una collezione dopo che è stato modificato.Se il sottostante collezione è destinata a cambiare, è possibile creare una luce wrapper che enumera la raccolta in modo sicuro, o restituire una copia della raccolta.


3) Infine, se avete bisogno di esporre matrici, piuttosto che di livello superiore collezioni, allora si dovrebbe restituire una copia della matrice per impedire agli utenti di modifica (opzione #2 da originale la domanda):

private T[] myArray_;
public T[] GetMyArray( ) {
  T[] copy = new T[this.myArray_.Length];
  this.myArray_.CopyTo( copy, 0 );
  return copy;
  // Note: if you are using LINQ, calling the 'ToArray( )' 
  //  extension method will create a copy for you.
}

Non si dovrebbe esporre la matrice sottostante attraverso una proprietà, in quanto non sarà in grado di dire quando gli utenti modificano.Per consentire la modifica della matrice, è possibile aggiungere un corrispondente SetMyArray( T[] array ) metodo, o utilizzare un custom indicizzatore:

public T this[int index] {
  get { return this.myArray_[index]; }
  set {
    // TODO: validate new value; raise change event; etc.
    this.myArray_[index] = value;
  }
}

(naturalmente, l'attuazione di un custom indicizzatore, sarà duplicare il lavoro di BCL classi :)

Altri suggerimenti

Io di solito andare per questo, un getter pubblico che restituisce Sistema.Collezioni.ObjectModel.ReadOnlyCollection:

public ReadOnlyCollection<SomeClass> Collection
{
    get
    {
         return new ReadOnlyCollection<SomeClass>(myList);
    }
}

Pubblici e metodi sull'oggetto per modificare l'insieme.

Clear();
Add(SomeClass class);

Se la classe è supposto per essere un repository per le altre persone a pasticciare con l'allora ho appena esporre la variabile privata come per il metodo #1 in quanto consente di risparmiare di scrivere la propria API, ma io tendo a rifuggire da che nel codice di produzione.

Se si sta semplicemente cercando di esporre una collezione sull'istanza, poi, utilizzando un getter/setter di un membro privato variabile sembra la soluzione più sensata per me (la prima opzione proposta).

Perché ti suggerisco di usare ReadOnlyCollection(T) è un compromesso?Se hai ancora bisogno di ottenere le notifiche di modifica dell'originale avvolto IList si potrebbe anche usare una ReadOnlyObservableCollection(T) per avvolgere la vostra collezione.Questo sarebbe meno di un compromesso nel tuo scenario?

Io sono un programmatore java, ma questo credo sia lo stesso per c#.

Non ho mai esporre una collezione privata di proprietà, perché le altre parti del programma può cambiare senza padre ne accorga, in modo che il metodo getter mi restituisce un array con gli oggetti della collezione e il metodo setter io chiamo un clearAll() oltre alla raccolta e quindi un addAll()

ReadOnlyCollection ancora ha lo svantaggio che il consumatore non può essere sicuro che la collezione originale non modificato in un momento inopportuno.Si possono invece usare Collezioni Immutabile.Se avete bisogno di fare un cambiamento, allora invece di cambiare l'originale, vi viene data una copia modificata.Il modo in cui è implementato, è competitivo con le prestazioni della mutevole collezioni.O meglio, se non hai la copia originale diverse volte a fare un certo numero di diversi (incompatibile) modifiche in seguito a ciascuna copia.

Mi consiglia di utilizzare il nuovo IReadOnlyList<T> e IReadOnlyCollection<T> Interfacce di esporre una collezione (richiede .NET 4.5).

Esempio:

public class AddressBook
{
    private readonly List<Contact> contacts;

    public AddressBook()
    {
        this.contacts = new List<Contact>();
    }

    public IReadOnlyList<Contact> Contacts { get { return contacts; } }

    public void AddContact(Contact contact)
    {
        contacts.Add(contact);
    }

    public void RemoveContact(Contact contact)
    {
        contacts.Remove(contact);
    }
}

Se è necessario per garantire che la raccolta non possono essere manipolati dall'esterno quindi prendere in considerazione ReadOnlyCollection<T> o le nuove collezioni Immutabile.

Evitare utilizzando l'interfaccia IEnumerable<T> esporre una collezione.Questa interfaccia non definisce alcuna garanzia che più le enumerazioni di svolgere bene.Se IEnumerable rappresenta una query quindi ogni enumerazione eseguire nuovamente la query.Gli sviluppatori che ottenere un'istanza di oggetto IEnumerable non so se rappresenta una raccolta o una query.

Di più su questo argomento si può leggere sul Pagina Wiki.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top