Suche…


Wörterbuch auflisten

Sie können auf drei verschiedene Arten durch ein Wörterbuch aufzählen:

Verwenden von KeyValue-Paaren

Dictionary<int, string> dict = new Dictionary<int, string>();
foreach(KeyValuePair<int, string> kvp in dict) 
{
   Console.WriteLine("Key : " + kvp.Key.ToString() + ", Value : " + kvp.Value);
}

Schlüssel verwenden

Dictionary<int, string> dict = new Dictionary<int, string>();
foreach(int key in dict.Keys)
{
    Console.WriteLine("Key : " + key.ToString() + ", Value : " + dict[key]);
}

Werte verwenden

Dictionary<int, string> dict = new Dictionary<int, string>();
foreach(string s in dict.Values)
{
    Console.WriteLine("Value : " + s);
}

Wörterbuch mit einem Collection-Initialisierer initialisieren

// Translates to `dict.Add(1, "First")` etc.
var dict = new Dictionary<int, string>()
{
    { 1, "First" },
    { 2, "Second" },
    { 3, "Third" }
};

// Translates to `dict[1] = "First"` etc.
// Works in C# 6.0.
var dict = new Dictionary<int, string>()
{
    [1] = "First",
    [2] = "Second",
    [3] = "Third"
};

Hinzufügen zu einem Wörterbuch

Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "First");
dict.Add(2, "Second");

// To safely add items (check to ensure item does not already exist - would throw)
if(!dict.ContainsKey(3))
{
   dict.Add(3, "Third");
}

Alternativ können sie über einen Indexer hinzugefügt / eingestellt werden. (Ein Indexer sieht intern aus wie eine Eigenschaft mit Get und Set, nimmt jedoch einen Parameter eines beliebigen Typs, der zwischen den Klammern angegeben ist.)

Dictionary<int, string> dict = new Dictionary<int, string>();
dict[1] = "First";
dict[2] = "Second";
dict[3] = "Third";

Im Gegensatz zur Add Methode, die eine Ausnahme auslöst, ersetzt der Indexer nur den vorhandenen Wert, wenn ein Schlüssel bereits im Wörterbuch enthalten ist.

Für threadsicheres Wörterbuch verwenden Sie ConcurrentDictionary<TKey, TValue> :

var dict = new ConcurrentDictionary<int, string>();
dict.AddOrUpdate(1, "First", (oldKey, oldValue) => "First");

Einen Wert aus einem Wörterbuch erhalten

Diesen Setup-Code gegeben:

var dict = new Dictionary<int, string>()
{
    { 1, "First" },
    { 2, "Second" },
    { 3, "Third" }
};

Sie können den Wert für die Eingabe mit der Taste 1 lesen möchten Wenn Schlüssel nicht vorhanden Wert bekommen werfen KeyNotFoundException , so können Sie für das mit dem ersten Scheck wollen ContainsKey :

if (dict.ContainsKey(1))
    Console.WriteLine(dict[1]);

Dies hat einen Nachteil: Sie durchsuchen Ihr Wörterbuch zweimal (einmal, um die Existenz zu prüfen und einmal, um den Wert zu lesen). Bei einem großen Wörterbuch kann sich dies auf die Leistung auswirken. Glücklicherweise können beide Operationen zusammen ausgeführt werden:

string value;
if (dict.TryGetValue(1, out value))
    Console.WriteLine(value);

Erstellen Sie ein Wörterbuch mit Case-Insensivitve-Tasten.

var MyDict = new Dictionary<string,T>(StringComparison.InvariantCultureIgnoreCase)

ConcurrentDictionary (ab .NET 4.0)

Stellt eine thread-sichere Sammlung von Schlüssel / Wert-Paaren dar, auf die mehrere Threads gleichzeitig zugreifen können.

Instanz erstellen

Das Erstellen einer Instanz funktioniert ähnlich wie bei Dictionary<TKey, TValue> , z. B .:

var dict = new ConcurrentDictionary<int, string>();

Hinzufügen oder Aktualisieren

Sie werden vielleicht überrascht sein, dass es keine Add Methode gibt, stattdessen AddOrUpdate mit zwei Überladungen:

(1) AddOrUpdate(TKey key, TValue, Func<TKey, TValue, TValue> addValue) - Fügt ein Schlüssel / Wert-Paar hinzu, wenn der Schlüssel noch nicht vorhanden ist, oder aktualisiert ein Schlüssel / Wert-Paar, wenn der Schlüssel verwendet wird ist bereits vorhanden.

(2) AddOrUpdate(TKey key, Func<TKey, TValue> addValue, Func<TKey, TValue, TValue> updateValueFactory) - Verwendet die angegebenen Funktionen, um ein Schlüssel / Wert-Paar zum Schlüssel hinzuzufügen, wenn der Schlüssel noch nicht vorhanden ist, oder bis Aktualisieren Sie ein Schlüssel / Wert-Paar, wenn der Schlüssel bereits vorhanden ist.

Einen Wert hinzufügen oder aktualisieren, unabhängig davon, welcher Wert vorhanden war, wenn er für den angegebenen Schlüssel bereits vorhanden war (1):

string addedValue = dict.AddOrUpdate(1, "First", (updateKey, valueOld) => "First");

Einen Wert hinzufügen oder aktualisieren, aber jetzt den Wert in update ändern, basierend auf dem vorherigen Wert (1):

string addedValue2 = dict.AddOrUpdate(1, "First", (updateKey, valueOld) => $"{valueOld} Updated");

Mit der Überladung (2) können wir auch eine neue Fabrik hinzufügen:

string addedValue3 = dict.AddOrUpdate(1, (key) => key == 1 ? "First" : "Not First", (updateKey, valueOld) => $"{valueOld} Updated");

Wert bekommen

Einen Wert zu erhalten ist derselbe wie beim Dictionary<TKey,TValue> :

string value = null;
bool success = dict.TryGetValue(1, out value);

Einen Wert abrufen oder hinzufügen

Es gibt zwei Überladungen, die einen Wert fadensicher abrufen oder hinzufügen .

Holen Sie sich den Wert mit Taste 2 oder fügen Sie den Wert "Second" hinzu, wenn der Schlüssel nicht vorhanden ist:

string theValue = dict.GetOrAdd(2, "Second");

Verwenden einer Factory zum Hinzufügen eines Werts, wenn kein Wert vorhanden ist:

string theValue2 = dict.GetOrAdd(2, (key) => key == 2 ? "Second" : "Not Second." );

IEnumerable to Dictionary (≥ .NET 3.5)

Erstellen Sie ein Wörterbuch <TKey, TValue> aus einem IEnumerable <T> :

using System;
using System.Collections.Generic;
using System.Linq;

public class Fruits
{
    public int Id { get; set; }
    public string Name { get; set; }
}

var fruits = new[]
{ 
    new Fruits { Id = 8 , Name = "Apple" },
    new Fruits { Id = 3 , Name = "Banana" },
    new Fruits { Id = 7 , Name = "Mango" },
};


// Dictionary<int, string>                  key      value
var dictionary = fruits.ToDictionary(x => x.Id, x => x.Name);

Aus einem Wörterbuch entfernen

Diesen Setup-Code gegeben:

var dict = new Dictionary<int, string>()
{
    { 1, "First" },
    { 2, "Second" },
    { 3, "Third" }
};

Verwenden Sie die Remove Methode, um einen Schlüssel und den zugehörigen Wert zu entfernen.

bool wasRemoved = dict.Remove(2);

Durch Ausführen dieses Codes werden der Schlüssel 2 und sein Wert aus dem Wörterbuch entfernt. Remove gibt einen booleschen Wert zurück, der angibt, ob der angegebene Schlüssel gefunden und aus dem Wörterbuch entfernt wurde. Wenn der Schlüssel nicht im Wörterbuch vorhanden ist, wird nichts aus dem Wörterbuch entfernt, und es wird false zurückgegeben (es wird keine Ausnahme ausgelöst).

Es ist falsch , einen Schlüssel zu versuchen und zu entfernen, indem der Wert für den Schlüssel auf null .

dict[2] = null; // WRONG WAY TO REMOVE!

Der Schlüssel wird dadurch nicht entfernt. Der vorherige Wert wird einfach durch den Wert null .

Um alle Schlüssel und Werte aus einem Wörterbuch zu entfernen, verwenden Sie die Clear Methode.

dict.Clear();

Nach der Ausführung von Clear der Count des Wörterbuchs 0, die interne Kapazität bleibt jedoch unverändert.

ContainsKey (TKey)

Um zu überprüfen, ob ein Dictionary einen bestimmten Schlüssel hat, können Sie die Methode ContainsKey(TKey) und den Schlüssel des Typs TKey . Die Methode gibt einen bool Wert zurück, wenn der Schlüssel im Wörterbuch vorhanden ist. Für probe:

var dictionary = new Dictionary<string, Customer>()
{
   {"F1", new Customer() { FirstName = "Felipe", ... } },
   {"C2", new Customer() { FirstName = "Carl", ... } },
   {"J7", new Customer() { FirstName = "John", ... } },
   {"M5", new Customer() { FirstName = "Mary", ... } },
};

Und prüfen Sie, ob ein C2 im Wörterbuch vorhanden ist:

if (dictionary.ContainsKey("C2")) 
{
   // exists
}

Die ContainsKey-Methode ist in der generischen Version Dictionary<TKey, TValue> .

Wörterbuch zur Liste

Erstellen einer Liste von KeyValuePair:

Dictionary<int, int> dictionary = new Dictionary<int, int>();
List<KeyValuePair<int, int>> list = new List<KeyValuePair<int, int>>();
list.AddRange(dictionary);

Erstellen einer Schlüsselliste:

Dictionary<int, int> dictionary = new Dictionary<int, int>();
List<int> list = new List<int>();
list.AddRange(dictionary.Keys);

Erstellen einer Liste von Werten:

Dictionary<int, int> dictionary = new Dictionary<int, int>();
List<int> list = new List<int>();
list.AddRange(dictionary.Values);

ConcurrentDictionary, erweitert mit Lazy'1, reduziert doppelte Berechnungen

Problem

ConcurrentDictionary glänzt, wenn es darum geht, vorhandene Schlüssel aus dem Cache (meistens ohne Sperren) zurückzugeben und auf einer granularen Ebene zu kämpfen. Was aber, wenn die Objekterstellung wirklich teuer ist und die Kosten für das Kontextwechseln überwiegen und einige Cache-Fehler auftreten?

Wenn derselbe Schlüssel von mehreren Threads angefordert wird, wird eines der Objekte, die aus kollidierenden Operationen resultieren, schließlich der Auflistung hinzugefügt, und die anderen werden verworfen, wodurch die CPU-Ressource für das Erstellen des Objekts und der Speicherressource für das temporäre Speichern des Objekts verschwendet wird . Andere Ressourcen könnten ebenfalls verschwendet werden. Das ist wirklich schlimm.

Lösung

Wir können ConcurrentDictionary<TKey, TValue> mit Lazy<TValue> . Die Idee ist, dass die ConcurrentDictionary-Methode GetOrAdd nur den Wert zurückgeben kann, der der Auflistung tatsächlich hinzugefügt wurde. Das Verlieren von Lazy-Objekten könnte auch in diesem Fall verschwendet werden, was aber kein großes Problem darstellt, da das Lazy-Objekt selbst relativ teuer ist. Die Value-Eigenschaft des verlierenden Lazy wird nie angefordert, da wir nur die Value-Eigenschaft der der Collection tatsächlich hinzugefügten Eigenschaft anfordern können - derjenigen, die von der GetOrAdd-Methode zurückgegeben wird:

public static class ConcurrentDictionaryExtensions
{
    public static TValue GetOrCreateLazy<TKey, TValue>(
        this ConcurrentDictionary<TKey, Lazy<TValue>> d,
        TKey key,
        Func<TKey, TValue> factory)
    {
        return
            d.GetOrAdd(
                key,
                key1 =>
                    new Lazy<TValue>(() => factory(key1),
                    LazyThreadSafetyMode.ExecutionAndPublication)).Value;
    }
}

Das Zwischenspeichern von XmlSerializer-Objekten kann besonders teuer sein und auch beim Start der Anwendung gibt es viele Konflikte. Dazu gehört noch mehr: Wenn es sich um benutzerdefinierte Serialisierer handelt, wird auch für den Rest des Prozesslebenszyklus ein Speicherverlust entstehen. Der einzige Vorteil von ConcurrentDictionary besteht in diesem Fall darin, dass für den Rest des Prozesslebenszyklus keine Sperren vorhanden sind, der Anwendungsstart und die Speicherverwendung jedoch nicht akzeptabel sind. Dies ist ein Job für unser ConcurrentDictionary, ergänzt mit Lazy:

private ConcurrentDictionary<Type, Lazy<XmlSerializer>> _serializers =
    new ConcurrentDictionary<Type, Lazy<XmlSerializer>>();

public XmlSerializer GetSerialier(Type t)
{
    return _serializers.GetOrCreateLazy(t, BuildSerializer);
}

private XmlSerializer BuildSerializer(Type t)
{
    throw new NotImplementedException("and this is a homework");
}


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow