Ich gebe einen Verweis auf ein Wörterbuch in meiner schreibgeschützten Eigenschaft zurück. Wie verhindere ich, dass Verbraucher meine Daten ändern? Wenn dies ein wäre, IList
könnte ich es einfach zurückgeben AsReadOnly
. Gibt es etwas Ähnliches, das ich mit einem Wörterbuch machen kann?
Private _mydictionary As Dictionary(Of String, String)
Public ReadOnly Property MyDictionary() As Dictionary(Of String, String)
Get
Return _mydictionary
End Get
End Property
.net
dictionary
readonly
Rob Sobers
quelle
quelle
Antworten:
Hier ist eine einfache Implementierung, die ein Wörterbuch umschließt:
quelle
.NET 4.5
Die .NET Framework 4.5 BCL wird eingeführt
ReadOnlyDictionary<TKey, TValue>
( Quelle ).Da die .NET Framework 4.5 BCL keine
AsReadOnly
Wörterbücher enthält, müssen Sie Ihre eigenen schreiben (wenn Sie dies möchten). Es wäre ungefähr das Folgende, dessen Einfachheit vielleicht deutlich macht, warum es für .NET 4.5 keine Priorität hatte..NET 4.0 und niedriger
Vor .NET 4.5 gibt es keine .NET Framework-Klasse,
Dictionary<TKey, TValue>
die eine Liste wie die ReadOnlyCollection umschließt . Es ist jedoch nicht schwierig, eine zu erstellen.Hier ist ein Beispiel - es gibt viele andere, wenn Sie Google für ReadOnlyDictionary .
quelle
AsReadOnly()
übliche Methode zu entwickelnDictionary<,>
, also frage ich mich, wie viele Menschen ihren neuen Typ entdecken werden. Dieser Stapelüberlauf-Thread hilft jedoch.Auf der jüngsten BUILD-Konferenz wurde bekannt gegeben, dass die Schnittstelle seit .NET 4.5
System.Collections.Generic.IReadOnlyDictionary<TKey,TValue>
enthalten ist. Der Beweis ist hier (Mono) und hier (Microsoft);)Ich bin mir nicht sicher, ob
ReadOnlyDictionary
es auch enthalten ist, aber zumindest mit der Schnittstelle sollte es nicht schwierig sein, jetzt eine Implementierung zu erstellen, die eine offizielle generische .NET-Schnittstelle verfügbar macht :)quelle
ReadOnlyDictionary<TKey, TValue>
(.Net 4.5) - msdn.microsoft.com/en-us/library/gg712875.aspxFühlen Sie sich frei, meine einfache Hülle zu verwenden. IDictionary wird NICHT implementiert, daher müssen zur Laufzeit keine Ausnahmen für Wörterbuchmethoden ausgelöst werden, die das Wörterbuch ändern würden. Änderungsmethoden sind einfach nicht da. Ich habe dafür meine eigene Schnittstelle namens IReadOnlyDictionary erstellt.
quelle
IDictionary
Vertrages. Ich denke, es ist aus OOP-Sicht korrekter, vonIDictionary
zu erbenIReadOnlyDictionary
.IDictionary
(für aktuellIReadOnlyDictionary
) undIMutableDictionary
(für aktuellIDictionary
) zu haben.IsReadOnly on
IDictionary<TKey,TValue>
wird vonICollection<T>
(IDictionary<TKey,TValue>
erweitertICollection<T>
alsICollection<KeyValuePair<TKey,TValue>>
) geerbt . Es wird in keiner Weise verwendet oder implementiert (und wird tatsächlich durch die explizite Implementierung der zugehörigenICollection<T>
Mitglieder "versteckt" ).Es gibt mindestens drei Möglichkeiten, um das Problem zu lösen:
IDictionary<TKey, TValue>
und verpacken / delegieren Sie es wie vorgeschlagen in ein inneres WörterbuchICollection<KeyValuePair<TKey, TValue>>
Satz als schreibgeschützt oderIEnumerable<KeyValuePair<TKey, TValue>>
abhängig von der Verwendung des Werts zurück.ctor(IDictionary<TKey, TValue>)
und geben Sie eine Kopie zurück. Auf diese Weise kann der Benutzer nach Belieben damit umgehen und hat keinen Einfluss auf den Status des Objekts, in dem sich das Quellwörterbuch befindet. Beachten Sie, dass Sie, wenn das zu klonende Wörterbuch Referenztypen enthält (keine Zeichenfolgen wie im Beispiel gezeigt), das Kopieren "manuell" durchführen und auch die Referenztypen klonen müssen.Nebenbei; Versuchen Sie beim Offenlegen von Sammlungen, die kleinstmögliche Schnittstelle verfügbar zu machen. Im Beispielfall sollte es sich um IDictionary handeln, da Sie so die zugrunde liegende Implementierung variieren können, ohne den öffentlichen Vertrag zu brechen, den der Typ verfügbar macht.
quelle
Ein schreibgeschütztes Wörterbuch kann bis zu einem gewissen Grad durch Folgendes ersetzt werden
Func<TKey, TValue>
: Ich verwende dies normalerweise in einer API, wenn ich nur möchte, dass Personen Suchvorgänge durchführen. Es ist einfach und insbesondere einfach, das Backend zu ersetzen, falls Sie dies jemals wünschen. Die Liste der Schlüssel wird jedoch nicht angezeigt. Ob das wichtig ist, hängt davon ab, was Sie tun.quelle
Nein, aber es wäre einfach, deine eigenen zu rollen. IDictionary definiert eine IsReadOnly-Eigenschaft. Wickeln Sie einfach ein Wörterbuch ein und lösen Sie eine NotSupportedException aus den entsprechenden Methoden aus.
quelle
Keine in der BCL verfügbar. Ich habe jedoch ein ReadOnlyDictionary (mit dem Namen ImmutableMap) in meinem BCL-Extras-Projekt veröffentlicht
Es ist nicht nur ein vollständig unveränderliches Wörterbuch, sondern unterstützt auch die Erstellung eines Proxy-Objekts, das IDictionary implementiert und an jedem Ort verwendet werden kann, an dem IDictionary verwendet wird. Es wird eine Ausnahme ausgelöst, wenn eine der mutierenden APIs aufgerufen wird
quelle
Sie können eine Klasse erstellen, die nur eine teilweise Implementierung des Wörterbuchs implementiert und alle Funktionen zum Hinzufügen / Entfernen / Festlegen verbirgt.
Verwenden Sie intern ein Wörterbuch, an das die externe Klasse alle Anforderungen weiterleitet.
Da Ihr Wörterbuch wahrscheinlich Referenztypen enthält, können Sie den Benutzer auf keinen Fall daran hindern, Werte für die vom Wörterbuch gehaltenen Klassen festzulegen (es sei denn, diese Klassen selbst sind schreibgeschützt).
quelle
Ich glaube nicht, dass es einen einfachen Weg gibt ... Wenn Ihr Wörterbuch Teil einer benutzerdefinierten Klasse ist, können Sie dies mit einem Indexer erreichen:
quelle
+1 Großartige Arbeit, Thomas. Ich bin mit ReadOnlyDictionary noch einen Schritt weiter gegangen.
Ähnlich wie Dale-Lösung, wollte ich entfernen
Add()
,Clear()
,Remove()
, etc von IntelliSense. Aber ich wollte, dass meine abgeleiteten Objekte implementiert werdenIDictionary<TKey, TValue>
.Außerdem möchte ich, dass der folgende Code kaputt geht: (Auch dies macht Dales Lösung)
Die Zeile Add () führt zu:
Der Anrufer kann es weiterhin übertragen
IDictionary<TKey, TValue>
, aber dasNotSupportedException
wird ausgelöst, wenn Sie versuchen, die nicht schreibgeschützten Mitglieder zu verwenden (aus Thomas 'Lösung).Wie auch immer, hier ist meine Lösung für alle, die dies auch wollten:
quelle
Jetzt gibt es Microsoft Immutable Collections (
System.Collections.Immutable
). Erhalten Sie sie über NuGet .quelle
quelle
public IEnumerable<KeyValuePair<string, string>> MyDictionary() { return _mydictionary; }
Dies ist eine schlechte Lösung, siehe unten.
Für diejenigen, die noch .NET 4.0 oder früher verwenden, habe ich eine Klasse, die genau wie die in der akzeptierten Antwort funktioniert, aber viel kürzer ist. Es erweitert das vorhandene Dictionary-Objekt und überschreibt (tatsächlich versteckt) bestimmte Mitglieder, damit sie beim Aufruf eine Ausnahme auslösen.
Wenn der Aufrufer versucht, Add, Remove oder eine andere Mutationsoperation des integrierten Wörterbuchs aufzurufen, gibt der Compiler einen Fehler aus. Ich verwende die veralteten Attribute, um diese Compilerfehler auszulösen. Auf diese Weise können Sie ein Wörterbuch durch dieses ReadOnlyDictionary ersetzen und sofort erkennen, wo Probleme auftreten können, ohne Ihre Anwendung ausführen und auf Laufzeitausnahmen warten zu müssen.
Schau mal:
Diese Lösung weist ein Problem auf, auf das @supercat hier hinweist:
Anstatt wie erwartet einen Fehler bei der Kompilierung oder eine von mir erhoffte Laufzeitausnahme anzugeben, wird dieser Code fehlerfrei ausgeführt. Es werden vier Zahlen gedruckt. Das macht mein ReadOnlyDictionary zu einem ReadWriteDictionary.
quelle
Dictionary<TKey,TValue>
ohne Compiler-Beschwerde erwartet , und das Umwandeln oder Erzwingen eines Verweises auf den Typ des einfachen Wörterbuchs alle Schutzmaßnahmen aufhebt.Dictionary
mit einerClone
Methode, die an eine Kette gekettet war , eine Ableitung daraus gemacht habeMemberwiseClone
. Leider sollte, während es effizient möglich sein Klon ein Wörterbuch , indem Sie die Hintergrundspeicher Klonen, die Tatsache , dass die Hintergrundspeicher sindprivate
eher alsprotected
Mittel dort für eine abgeleitete Klasse Klon sie keinen Weg;MemberwiseClone
Wenn Sie die Hintergrundspeicher verwenden, ohne sie auch zu klonen, wird der Klon durch nachfolgende Änderungen am ursprünglichen Wörterbuch beschädigt, und durch Änderungen am Klon wird das Original beschädigt.