2010-12-09 9 views
5

Wenn eine Setter für eine Eigenschaft List Umsetzung (in C#) ist es eine schlechte Sache zu schreiben als:List-Eigenschaft Setter

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

Up:

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

Sollte es nicht geschrieben werden Bis heute habe ich das erstere verwendet, aber ich habe kürzlich einen Code gefunden, der letzteres verwendet und es scheint, dass dies wahrscheinlich der richtige Weg ist, dies zu implementieren.

Verwendet nicht die erstere, da die TheList-Eigenschaft geändert wird, wenn Änderungen an der externen Liste vorgenommen werden, die ihr zugewiesen wird. Zum Beispiel:

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

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

die ehemalige Verwendung wird nicht der folgende Code die Verkapselung von theList brechen:

list.Clear(); 

Jetzt c.TheList ist auch leer, was nicht sein kann, was wir wollten. Unter Verwendung des letzteren Ansatzes würde c.Liste jedoch nicht gelöscht werden.

+0

Nein, zweite Lösung ist nicht korrekt. Verwenden Sie die erste Lösung und, wenn Sie eine Kopie anstelle einer Referenz festlegen möchten - schreiben Sie c.TheList = new List (Liste); – vorrtex

+1

Das hängt von Ihrer Besitz-Semantik ab. Einige Anrufer erwarten möglicherweise, dass sie in der Lage sind, die Liste zu setzen und sie "von außen" zu aktualisieren. Welchen Pfad Sie auch immer nehmen, dokumentieren Sie ihn entsprechend. –

+0

Danke für die tollen Antworten. Ich bin froh, dass ich den zweiten Ansatz nicht verwendet habe, ohne zuerst zu prüfen. Es scheint, dass der Konsens darin besteht, in den meisten Fällen keinen Setter bereitzustellen oder ihn zumindest zu schützen. – mikesigs

Antwort

7

Collection properties should be readonly.

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

EDIT: Erläuterungen:

Wenn anderer Code kopiert ein Verweis auf die Liste (zB var list = Thingy.TheList), kann es, wenn Sie die Eigenschaft auf eine andere Liste fertig vermasselt. (Es wird enden, eine Waise zu halten)
Im Allgemeinen gibt es sehr wenige Gründe, Menschen zu erlauben, einen Eigenschaftspunkt zu einer anderen Sammlungsinstanz zu machen.

Mit Collection<T> anstelle von List<T> können Sie Änderungen an der Sammlung abfangen und Validierung hinzufügen oder übergeordnete Felder beibehalten. (Sie erben Collection<T> und überschreiben und andere Methoden) Sie können solche Logik auch nach dem Versand einer Bibliothek hinzufügen, ohne den aufrufenden Code zu beschädigen.

+2

Oder verfügbar als 'ReadOnlyCollection ', 'List ' hat eine AsReadOnly() -Methode, um es einfach zu machen, die Rückkehr zu tun. – pstrjds

+0

Kennen Sie gute Artikel, die erklären, warum diese beiden Prinzipien gelten? Ich sehe nicht vollständig, was falsch ist mit einer beschreibbaren Liste als eine Eigenschaft. – JeremyWeir

+0

@jayrdub: Hier gehst du. – SLaks

3

Es hängt vollständig davon ab, wie Sie Ihre Immobilie betreiben möchten. Wenn Sie eine Kopie möchten, erstellen Sie eine Kopie. Ansonsten nicht. Oftmals werden Eigenschaften wie diese keinen Setter verfügbar machen, da das Ersetzen der gesamten Liste keine gewünschte Aktion für diesen Fall ist.

Natürlich ist die Verwendung Ihrer zweiten Methode möglicherweise ein Performance-Problem, da die Eigenschaftssyntax die Tatsache ausschließt, dass Sie jedes Mal, wenn Sie den Setter verwenden, vollständig eine neue Liste erstellen und erstellen.

0

Zunächst einmal sind beide etwas inkorrekt. Öffentliche Eigenschaften sollten wirklich als IList verfügbar gemacht werden, da List implementierungsspezifisch ist (fxcop wird Sie tatsächlich warnen, wenn Sie List als öffentliche Eigenschaft verwenden).

Zweitens, wenn möglich würde ich die Setter privat sein. Mit dem Getter kann ein Benutzer trotzdem hinzufügen/entfernen/löschen/etc. aber vereinfacht die Probleme, die Sie in Ihrer Frage aufgeworfen haben.

+0

Normalerweise verwende ich IList, aber da wir im zweiten Ansatz explizit neue List() verwenden, dachte ich, dass es sinnvoller ist, die Eigenschaft als solche zu definieren. – mikesigs

+0

Ich habe gerade festgestellt, dass IList nicht die Methode AddRange enthält, die ich will. Nur die List Implementierung enthält diese Methode. Also warum sollte ich diese Eigenschaft nicht als eine Liste verfügbar machen. – mikesigs

6

Ich glaube, da eine Liste ein Referenzobjekt ist, brauchen Sie nur die Referenz zu bekommen.Also:

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

Sobald Sie die Referenz haben, und Änderungen an der Sammlung, sind Ändern Sie _TheList

0

Ich glaube nicht, gibt es eine universelle Antwort auf Ihre Frage. Das Verhalten, das Sie beschreiben, kann oder kann nicht das sein, was Sie wollen.

Im Allgemeinen bin ich mit SLaks, dass es sauberer ist es, die Sammlungen Eigenschaften schreibgeschützt zu halten, aber es hängt alles

0

Ich bin nicht sicher, ob ich das richtig verstanden. Aber ich mache es so:

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

Sie haben also eine Liste, die Sie in ein Array und dann zurück in eine Liste konvertieren? Wie bereits von vielen Kommentatoren vereinbart wurde, möchten Sie die Liste normalerweise nicht über einen Setter verfügbar machen, den Sie benötigen würden, um das zu tun, was Sie vorgeschlagen haben. Können Sie mehr erklären, was Sie hier vorschlagen? – mikesigs