Gibt es einen Grund, eine interne Sammlung als ReadOnlyCollection und nicht als IEnumerable verfügbar zu machen, wenn der aufrufende Code nur die Sammlung durchläuft?
class Bar
{
private ICollection<Foo> foos;
// Which one is to be preferred?
public IEnumerable<Foo> Foos { ... }
public ReadOnlyCollection<Foo> Foos { ... }
}
// Calling code:
foreach (var f in bar.Foos)
DoSomething(f);
Aus meiner Sicht ist IEnumerable eine Teilmenge der Schnittstelle von ReadOnlyCollection und erlaubt dem Benutzer nicht, die Sammlung zu ändern. Wenn also die IEnumberable-Schnittstelle ausreicht, ist dies die zu verwendende. Ist das eine richtige Art, darüber nachzudenken, oder fehlt mir etwas?
Danke / Erik
c#
.net
collections
ienumerable
readonly-collection
Erik Öjebo
quelle
quelle
ReadOnlyCollection
umschließen, wenn Sie paranoid sind, aber jetzt sind Sie nicht an eine bestimmte Implementierung gebunden.Antworten:
Modernere Lösung
Sofern die interne Sammlung nicht veränderbar sein muss, können Sie das
System.Collections.Immutable
Paket verwenden, Ihren Feldtyp in eine unveränderliche Sammlung ändern und diese dann direkt verfügbar machen - vorausgesetztFoo
natürlich, sie ist unveränderlich.Die Antwort wurde aktualisiert, um die Frage direkter zu beantworten
Es hängt davon ab, wie sehr Sie dem aufrufenden Code vertrauen. Wenn Sie die vollständige Kontrolle über alles haben, was dieses Mitglied jemals anrufen wird, und Sie garantieren, dass kein Code jemals verwendet wird:
Dann wird sicher kein Schaden angerichtet, wenn Sie die Sammlung direkt zurückgeben. Ich versuche im Allgemeinen, ein bisschen paranoider zu sein.
Ebenso, wie Sie sagen: Wenn Sie nur brauchen
IEnumerable<T>
, warum binden Sie sich dann an etwas Stärkeres?Ursprüngliche Antwort
Wenn Sie .NET 3.5 verwenden, können Sie das Erstellen einer Kopie und die einfache Umwandlung vermeiden, indem Sie einen einfachen Aufruf von Überspringen verwenden:
(Es gibt viele andere Optionen für das einfache Umbrechen - das Schöne an
Skip
Select / Where ist, dass es keinen Delegaten gibt, der für jede Iteration sinnlos ausgeführt werden kann.)Wenn Sie .NET 3.5 nicht verwenden, können Sie einen sehr einfachen Wrapper schreiben, um dasselbe zu tun:
quelle
ReadOnlyCollection
in ein umgewandeltICollection
und dannAdd
erfolgreich ausgeführt wird. Soweit ich weiß, sollte das nicht möglich sein. Dasevil.Add(...)
sollte einen Fehler auslösen. dotnetfiddle.net/GII2jWReadOnlyCollection
- ich besetze eine,IEnumerable<T>
die eigentlich nicht schreibgeschützt ist ... es ist, anstatt eine zu entlarvenReadOnlyCollection
ReadOnlyCollection
anstelle einesIEnumerable
zu verwenden, um sich vor dem bösen Casting zu schützen.Wenn Sie nur die Sammlung durchlaufen müssen:
dann reicht es aus, IEnumerable zurückzugeben .
Wenn Sie zufälligen Zugriff auf Elemente benötigen:
Wickeln Sie es dann in ReadOnlyCollection ein .
quelle
System.Collections.Immutable
gemäß den Empfehlungen von Jon Skeet ist absolut gültig, wenn Sie etwas verfügbar machen, das sich nie ändern wird, nachdem Sie einen Verweis darauf erhalten haben. Wenn Sie dagegen eine schreibgeschützte Ansicht einer veränderlichen Sammlung verfügbar machen, ist dieser Rat weiterhin gültig, obwohl ich ihn wahrscheinlich als verfügbar machen würdeIReadOnlyCollection
(was nicht existierte, als ich dies schrieb).bar.Foos[17]
mitIReadOnlyCollection
. Der einzige Unterschied ist zusätzlichesCount
Eigentum.public interface IReadOnlyCollection<out T> : IEnumerable<T>, IEnumerable
bar.Foos[17]
, müssen Sie es als aussetzenReadOnlyCollection<Foo>
. Wenn Sie die Größe kennen und durchlaufen möchten, legen Sie sie als offenIReadOnlyCollection<Foo>
. Wenn Sie die Größe nicht kennen müssen, verwenden SieIEnumerable<Foo>
. Es gibt andere Lösungen und andere Details, aber es würde den Rahmen der Diskussion dieser speziellen Antwort sprengen.Wenn Sie dies tun, hindert nichts Ihre Anrufer daran, die IEnumerable zurück in ICollection zu übertragen und sie dann zu ändern. ReadOnlyCollection entfernt diese Möglichkeit, obwohl es weiterhin möglich ist, über Reflektion auf die zugrunde liegende beschreibbare Sammlung zuzugreifen. Wenn die Sammlung klein ist, können Sie dieses Problem sicher und einfach umgehen, indem Sie stattdessen eine Kopie zurückgeben.
quelle
Ich vermeide es so oft wie möglich, ReadOnlyCollection zu verwenden. Es ist tatsächlich erheblich langsamer als nur die Verwendung einer normalen Liste. Siehe dieses Beispiel:
quelle
Manchmal möchten Sie möglicherweise eine Schnittstelle verwenden, möglicherweise, weil Sie die Sammlung während des Komponententests verspotten möchten. In meinem Blogeintrag finden Sie Informationen zum Hinzufügen Ihrer eigenen Benutzeroberfläche zu ReadonlyCollection mithilfe eines Adapters.
quelle