.NET Framework
ordböcker
Sök…
Räkna upp en ordlista
Du kan räkna upp i en ordlista på ett av tre sätt:
Använda KeyValue-par
Dictionary<int, string> dict = new Dictionary<int, string>();
foreach(KeyValuePair<int, string> kvp in dict)
{
Console.WriteLine("Key : " + kvp.Key.ToString() + ", Value : " + kvp.Value);
}
Använda nycklar
Dictionary<int, string> dict = new Dictionary<int, string>();
foreach(int key in dict.Keys)
{
Console.WriteLine("Key : " + key.ToString() + ", Value : " + dict[key]);
}
Använda värden
Dictionary<int, string> dict = new Dictionary<int, string>();
foreach(string s in dict.Values)
{
Console.WriteLine("Value : " + s);
}
Initiera en ordlista med en samlingsinitierare
// 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"
};
Lägga till i en ordlista
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");
}
Alternativt kan de läggas till / ställas in via en indexerare. (En indexerare ser internt ut som en egenskap, har en get och set, men tar en parameter av alla typer som anges mellan parenteserna):
Dictionary<int, string> dict = new Dictionary<int, string>();
dict[1] = "First";
dict[2] = "Second";
dict[3] = "Third";
Till skillnad från metoden Add
som kastar ett undantag, om en nyckel redan finns i ordboken, ersätter indexeraren bara det befintliga värdet.
Använd trådlös säker ordlista ConcurrentDictionary<TKey, TValue>
:
var dict = new ConcurrentDictionary<int, string>();
dict.AddOrUpdate(1, "First", (oldKey, oldValue) => "First");
Få ett värde från en ordlista
Med den här installationskoden:
var dict = new Dictionary<int, string>()
{
{ 1, "First" },
{ 2, "Second" },
{ 3, "Third" }
};
Du kanske vill läsa värdet för posten med nyckel 1. Om nyckeln inte finns att få ett värde kommer KeyNotFoundException
att kasta, så du kanske först vill kontrollera det med ContainsKey
:
if (dict.ContainsKey(1))
Console.WriteLine(dict[1]);
Detta har en nackdel: du söker igenom din ordlista två gånger (en gång för att kontrollera om det finns och en för att läsa värdet). För en stor ordbok kan detta påverka prestandan. Lyckligtvis kan båda operationerna utföras tillsammans:
string value;
if (dict.TryGetValue(1, out value))
Console.WriteLine(value);
Gör en ordbok med fodral-insensivitve-nycklar.
var MyDict = new Dictionary<string,T>(StringComparison.InvariantCultureIgnoreCase)
ConcurrentDictionary (från .NET 4.0)
Representerar en trådsäker samling av nyckel- / värdepar som kan nås av flera trådar samtidigt.
Skapa en instans
Att skapa en instans fungerar ungefär på samma sätt som med Dictionary<TKey, TValue>
, t.ex.
var dict = new ConcurrentDictionary<int, string>();
Lägga till eller uppdatera
Du kanske blir förvånad över att det inte finns någon Add
metod, men istället finns det AddOrUpdate
med två överbelastningar:
(1) AddOrUpdate(TKey key, TValue, Func<TKey, TValue, TValue> addValue)
- Lägger till ett nyckel- / värdepar om nyckeln inte redan finns, eller uppdaterar ett nyckel- / värdepar med hjälp av den angivna funktionen om tangenten existerar redan.
(2) AddOrUpdate(TKey key, Func<TKey, TValue> addValue, Func<TKey, TValue, TValue> updateValueFactory)
- använder de angivna funktionerna för att lägga till ett nyckel- / värdepar till om nyckeln inte redan finns, eller till uppdatera ett nyckel- / värdepar om nyckeln redan finns.
Lägga till eller uppdatera ett värde, oavsett vad som var värdet om det redan fanns för en given nyckel (1):
string addedValue = dict.AddOrUpdate(1, "First", (updateKey, valueOld) => "First");
Lägga till eller uppdatera ett värde, men ändra nu värdet i uppdateringen, baserat på föregående värde (1):
string addedValue2 = dict.AddOrUpdate(1, "First", (updateKey, valueOld) => $"{valueOld} Updated");
Med överbelastningen (2) kan vi också lägga till nytt värde med hjälp av en fabrik:
string addedValue3 = dict.AddOrUpdate(1, (key) => key == 1 ? "First" : "Not First", (updateKey, valueOld) => $"{valueOld} Updated");
Få värde
Att få ett värde är detsamma som med Dictionary<TKey,TValue>
:
string value = null;
bool success = dict.TryGetValue(1, out value);
Få eller lägga till ett värde
Det finns två överbelastningar av mehod, som kommer att få eller lägga till ett värde på ett tråd-säkert sätt.
Få värde med nyckel 2, eller lägg till värde "Second" om nyckeln inte finns:
string theValue = dict.GetOrAdd(2, "Second");
Använda en fabrik för att lägga till ett värde, om värdet inte finns:
string theValue2 = dict.GetOrAdd(2, (key) => key == 2 ? "Second" : "Not Second." );
IEnumerable to Dictionary (≥. NET 3.5)
Skapa en ordlista <TKey, TValue> från en 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);
Ta bort från en ordlista
Med den här installationskoden:
var dict = new Dictionary<int, string>()
{
{ 1, "First" },
{ 2, "Second" },
{ 3, "Third" }
};
Använd metoden Remove
för att ta bort en nyckel och dess tillhörande värde.
bool wasRemoved = dict.Remove(2);
Genom att använda den här koden tas nyckeln 2
och dess värde från ordboken. Remove
ger ett booleskt värde som anger om den angivna nyckeln hittades och tas bort från ordboken. Om nyckeln inte finns i ordboken tas inget bort från ordboken och falskt returneras (inget undantag kastas).
Det är felaktigt att försöka ta bort en nyckel genom att ställa in värdet för nyckeln till null
.
dict[2] = null; // WRONG WAY TO REMOVE!
Detta tar inte bort nyckeln. Det kommer bara att ersätta det föregående värdet med ett värde på null
.
Om du vill ta bort alla nycklar och värden från en ordlista använder du metoden Clear
.
dict.Clear();
Efter att ha rensat Clear
ordlistans Count
0, men den interna kapaciteten förblir oförändrad.
ContainsKey (TKey)
För att kontrollera om en Dictionary
har en specifik nyckel kan du ringa metoden ContainsKey(TKey)
och ange nyckeln av TKey
typ. Metoden returnerar ett bool
när nyckeln finns i ordboken. För prov:
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", ... } },
};
Och kontrollera om det finns en C2
i ordboken:
if (dictionary.ContainsKey("C2"))
{
// exists
}
Metoden ContainKey är tillgänglig i den generiska versionen Dictionary<TKey, TValue>
.
Ordbok till lista
Skapa en lista med KeyValuePair:
Dictionary<int, int> dictionary = new Dictionary<int, int>();
List<KeyValuePair<int, int>> list = new List<KeyValuePair<int, int>>();
list.AddRange(dictionary);
Skapa en lista med nycklar:
Dictionary<int, int> dictionary = new Dictionary<int, int>();
List<int> list = new List<int>();
list.AddRange(dictionary.Keys);
Skapa en lista med värden:
Dictionary<int, int> dictionary = new Dictionary<int, int>();
List<int> list = new List<int>();
list.AddRange(dictionary.Values);
ConcurrentDiction kompletterat med Lazy'1 minskar duplicerad beräkning
Problem
ConcurrentDictions lyser när det gäller att omedelbart återlämna befintliga nycklar från cache, mestadels låsfria och kämpa på en granulär nivå. Men vad händer om objekt skapandet är riktigt dyrt, uppväger kostnaden för kontextbyte och vissa cachemissningar uppstår?
Om samma nyckel begärs från flera trådar, kommer ett av de objekt som härrör från kolliderande operationer så småningom att läggas till samlingen, och de andra kommer att kastas bort, och slösa bort CPU-resursen för att skapa objektet och minnesresursen för att lagra objektet tillfälligt . Andra resurser kan också slösas bort. Det här är verkligen dåligt.
Lösning
Vi kan kombinera ConcurrentDictionary<TKey, TValue>
med Lazy<TValue>
. Tanken är att ConcurrentDictionary GetOrAdd-metoden bara kan returnera värdet som faktiskt lades till samlingen. De förlorade Lazy-objekten kan också slösas bort i det här fallet, men det är inte så mycket problem, eftersom Lazy-objektet i sig är relativt oskäligt. Värdeegenskapen för den förlorande Lazy begärs aldrig, eftersom vi är smarta att bara begära värdeegenskapen för den som faktiskt läggs till samlingen - den som returneras från GetOrAdd-metoden:
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;
}
}
Caching av XmlSerializer-objekt kan vara särskilt dyrt, och det är mycket stridighet vid programstart också. Och det finns mer med detta: om det är anpassade serier, kommer det att finnas ett minnesläckage också för resten av processens livscykel. Den enda fördelen med ConcurrentDiction i detta fall är att det för resten av processens livscykel inte finns några lås, men applikationsstart och minnesanvändning skulle vara oacceptabelt. Detta är ett jobb för vår ConcurrentDiction, kompletterad med 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");
}