Best Practice: Wie eine schreibgeschützte ICollection belichten
-
08-07-2019 - |
Frage
Ich habe eine ICollection<T>
foos
in meiner Klasse genannt, die ich als schreibgeschützt verfügbar machen möchten (siehe diese Frage ). Ich sehe, dass die Schnittstelle eine Eigenschaft .IsReadOnly
definiert, die ... angemessen scheint Meine Frage ist: Wie mache ich es für die Verbraucher der Klasse offensichtlich, dass foos
schreibgeschützt ist?
Ich möchte ein nicht umgesetztes Verfahren vor dem Versuch, wie .IsReadOnly
abfragen .Add()
nicht auf sie verlassen zu erinnern. Im Idealfall würde Ich mag foos
als ReadOnlyCollection<T>
aussetzen, aber nicht IList<T>
implementieren. Soll ich foo
über eine Methode aufgerufen, beispielsweise GetReadOnlyFooCollection
anstatt über eine Eigenschaft aussetzen? Wenn ja, würde verwechseln nicht jemand, der dann ein ReadOnlyCollection<T>
erwartet?
Dies ist C # 2.0, so Erweiterungsmethoden wie ToList()
nicht zur Verfügung steht ...
Lösung
scheine ich bei der Rückkehr IEnumerable mit den geklonten Objekte niedergelassen zu haben.
public IEnumerable<Foose> GetFooseList() {
foreach(var foos in Collection) {
yield return foos.Clone();
}
}
- erfordert eine Clone-Methode auf Foos.
Auf diese Weise können keine Änderungen in der Sammlung. Denken Sie daran, dass Readonlycollection „leaky“ ist, da die Objekte im Innern verändert werden können, wie in einem Link in einem anderen Beitrag erwähnt.
Andere Tipps
Sie können "Foos" ein Readonlycollection wie folgt vor:
ReadOnlyCollection<T> readOnlyCollection = foos.ToList<T>().AsReadOnly();
Dann können Sie es als eine Eigenschaft Ihrer Klasse aus.
EDIT:
class FooContainer
{
private ICollection<Foo> foos;
public ReadOnlyCollection<Foo> ReadOnlyFoos { get { return foos.ToList<Foo>().AsReadOnly();} }
}
Hinweis: Sie sollten bedenken, dass, sobald Sie die ReadOnlyFoos Sammlung bekommen, ist nicht mehr „synchronisiert“ mit Ihrem foos ICollection. Sehen Sie sich die Thread referenziert Sie .
Da die Frage geschrieben wurde, hat .NET 4.0 eine IReadOnlyCollection<T>
Schnittstelle hinzugefügt; es wäre wahrscheinlich gut sein, dass als deklarierten Rückgabetyp zu verwenden.
Das hat jedoch lassen die Frage offen, welche Art von Instanz zurückzukehren. Ein Ansatz wäre es, alle Elemente in der ursprünglichen Sammlung zu klonen. Eine andere wäre, immer einen Nur-Lese-Wrapper zurück. Eine dritte wäre die ursprüngliche Sammlung zurück, wenn es IReadOnlyCollection<T>
implementiert. Jeder Ansatz wird die beste in bestimmten Kontexten sein, wird aber weniger als ideal (oder vielleicht geradezu schrecklich) in anderen. Leider Microsoft bietet keine Standard Mittel, durch die eine Frage zwei sehr wichtige Fragen gestellt werden können:
-
Sie versprechen Sie immer und für immer die gleichen Elemente enthalten, wie Sie jetzt tun?
-
Können Sie sicher direkt an Code ausgesetzt werden, die angeblich nicht Ihre Inhalte zu ändern.
Welche Art von Verpackung ist angemessen, würde davon abhängen, was der Client-Code erwartet mit der Sache zu tun, die er empfängt. Einige Szenarien zu vermeiden:
-
Ein Objekt wurde von einem Typ geliefert, dass der Client als unveränderlich erkennen würde, aber anstatt direkt zurückgegeben wird es dupliziert wird, eine Art verwendet, dass der Client nicht als unveränderlich nicht erkennt. Folglich wird der Kunde gezwungen, wieder um die Sammlung zu kopieren.
-
Ein Objekt wurde von einem Typ geliefert, dass der Client als unveränderlich erkennen würde, aber bevor sie in einer solchen Art und Weise gewickelt wird zurückgegeben wird, dass der Client nicht sagen kann, ob die Sammlung unveränderlich ist oder nicht, und somit gezwungen, zu duplizieren.
-
Ein Objekt von wandelbarem Typ, die angeblich nicht mutiert werden soll, wird von einem Client (Guss zu einer Read-Only-Schnittstelle) geliefert. Es wird dann direkt an einem anderen Kunden ausgesetzt, die feststellen, dass es ein veränderlicher Typ ist, und geht es zu ändern.
-
Ein Verweis auf eine veränderbare Sammlung empfangen wird, und ist in einem Nur-Lese-Wrapper eingekapselt, bevor an einem Kunden zurückgegeben werden, die ein unveränderliches Objekt benötigt. Die Methode, die die Sammlung zurückgegeben versprochen, dass sie unveränderlich ist, und somit ging der Kunde seine eigene Verteidigungs Kopie. Der Kunde ist dann schlecht vorbereitet für die Möglichkeit, dass die Sammlung ändern könnte.
Es ist nicht wirklich besonders „sicher“ Vorgehensweise ein Objekt mit Sammlungen nehmen, die sie von einigen Kunden erhalten und muss andere belichten. Immer Duplizieren alles in vielen Fällen ist die sicherste Vorgehensweise, aber es kann in Situationen leicht führen, wo eine Sammlung, die nicht benötigen, sollte überhaupt endet immer dupliziert hunderte oder tausende Male dupliziert werden. Wiederkehrende Referenzen wie empfangen kann oft der effizienteste Ansatz sein, aber es kann auch semantisch gefährlich sein.
möchte ich Microsoft die Standardmittel hinzufügen würde, durch die Sammlungen die oben genannten Fragen oder noch besser gestellt werden könnten, aufgefordert werden, eine unveränderliche Momentaufnahme ihrer aktuellen Zustand zu erzeugen. Eine unveränderliche Sammlung sehr billig eine unveränderliche Momentaufnahme der aktuellen Zustand zurückkehren konnte (nur selbst zurück) und sogar einige wandelbar Sammlungstypen könnte eine unveränderliche Snapshot zu einem Preis weit unter den Kosten einer vollständigen Aufzählung zurückgeben (zB ein List<T>
könnte durch zwei gesichert werden T[][]
Arrays, von denen Verweise auf gemeinsam nutzbare unveränderliche Arrays von 256 Elementen enthält, und von denen die andere halten Verweise auf unsharable veränderbare Arrays von 256 Elementen. eine Momentaufnahme von einer Liste zu machen würde nur die innere Arrays enthält Elemente Klonieren erfordern, die modifiziert wurde, . seit dem letzten Snapshot - möglicherweise viel billiger als die ganze Liste Klonen Leider, da keine Standard-Schnittstelle gibt es „eine unveränderliche Schnappschuss machen“ [dass ICloneable
beachten Sie zählt nicht, da ein Klon einer wandelbaren Liste wandelbar wäre, während ein machen eine könnteunveränderliche Snapshot durch einen wandelbaren Klon in einem Read-Only-Wrapper einkapseln, das wäre nur für die Dinge funktionieren, die klonbar sind, und sogar Arten, die nicht klonbar sind, sollten nach wie vor eine „veränderliches Snapshot“ -Funktion unterstützen.]
Meine Empfehlung ist direkt Gebrauch ein Readonlycollection
Normalerweise würde ich vorschlagen, die entsprechende Schnittstelle. Aber da das .NET Framework nicht zur Zeit eine geeignete IReadOnlyCollection hat, müssen Sie mit dem Readonlycollection Typ gehen.
Auch Sie müssen sich bewusst sein, wenn Readonlycollection verwenden, weil es eigentlich nicht schreibgeschützt ist: Unveränderlichkeit und Readonlycollection
Manchmal können Sie eine Schnittstelle verwenden, vielleicht, weil Sie die Sammlung während Unit-Tests verspotten wollen. Bitte beachten Sie meine Blog-Eintrag rel="nofollow für die eigene Schnittstelle zu Readonlycollection Zugabe unter Verwendung von ein Adapter.
ich in der Regel ein IEnumerable<T>
zurück.
Wenn Sie eine Sammlung nur lesbar machen (so Methoden wie Add
, Remove
und Clear
funktioniert nicht mehr) gibt es nicht mehr viel übrig, dass eine Sammlung unterstützt, dass ein zählbaren nicht -. Nur Count
und Contains
, glaube ich
Wenn die Verbraucher der Klasse wirklich Elemente müssen behandeln, wie sie in einer Sammlung sind, ist es einfach genug, um einen IEnumerable
zu List<T>
Konstruktor zu übergeben.
Zurück a T []:
private ICollection<T> items;
public T[] Items
{
get { return new List<T>(items).ToArray(); }
}