ich habe ungefähr folgenden Code:
public class Parser
{
private Dictionary<Thread, bool> iWorkingThreads = new
Dictionary<Thread, bool>();
public void load()
{
int tMaxThreads = 5;
Thread tThread = null;
for (int tCounter = 0; tCounter < tMaxThreads; tCounter++)
{
tThread = new Thread(parse);
tThread.Name = "ParsingThread-" + tCounter;
tThread.IsBackground = true;
tThread.SetApartmentState(ApartmentState.STA);
tThread.Start();
iWorkingThreads.Add(tThread, true);
}
}
}
*********************************************************************
Das führt zu folgender Exception:
System.ArgumentException: Ein Element mit dem gleichen Schlüssel wurde
bereits hinzugefügt.
bei System.ThrowHelper.ThrowArgumentException(ExceptionResource
resource)
bei System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue
value, Boolean add)
bei System.Collections.Generic.Dictionary`2.Add(TKey key, TValue
value)
bei LogfileParser.Parser.load() in E:\wissen\csharp\Projekte
\LogfileParser\src\controller\Parser.cs:Zeile 77.
Was ich ziemlich unentspannt finde, weil der hinzugefügte Schlüssel ja
in jedem Schleifendurchlauf neu erzeugt wird.
Ich habe da jetzt schon einige Zeit drüber sinniert, aber ich verstehe
einfach nicht, warum es passiert.
Wäre sehr dankbar für jede Hilfe
Sonnige Grüße,
Christoph
> tThread = new Thread(parse);
wie ist 'parse' implementiert?
Mache ein minimal reproduzierbares Beispiel.
ciao Frank
--
Dipl.Inf. Frank Dzaebel [MCP/MVP C#]
http://Dzaebel.NET
Hi Frank,
ich hab tatsächlich den Fehler gefunden und behoben.
Was mich allerdings zu der Frage führt: Wie ist denn das
Standardverfahren in C#, um einen Wert in einem Dictionary zu
aktualisieren?
Löscht man vorher den alten Wert? Oder nutzt man immer Dictionary
["Key"] = "value"; anstelle von Add?
> Was mich allerdings zu der Frage f�hrt: Wie ist denn das
> Standardverfahren in C#, um einen Wert in einem Dictionary zu
> aktualisieren?
>
> L�scht man vorher den alten Wert? Oder nutzt man immer Dictionary
> ["Key"] = "value"; anstelle von Add?
Nein, den Wert vorher rauszul�schen und dann mit Add() wieder
hinzuzuf�gen
dict.Remove(key);
dict.Add(key, newValue);
w�re zwar m�glich, ist aber weniger effizient. Daher einfach:
dict[key] = newValue;
--
Immo Landwerth
> > wie ist 'parse' implementiert?
> > Mache ein minimal reproduzierbares Beispiel.
>
> Hi Frank,
>
> ich hab tatsächlich den Fehler gefunden und behoben.
schön.
> Was mich allerdings zu der Frage führt: Wie ist denn das
> Standardverfahren in C#, um einen Wert in einem Dictionary zu
> aktualisieren?
> Löscht man vorher den alten Wert? Oder nutzt man immer Dictionary
> ["Key"] = "value"; anstelle von Add?
Natürlich: DeinDictionary["key"] = wert;
wenn Du wirklich "aktualisieren" meinst.
Denn 'Add' würde ja *anfügen* und nicht den Wert aktualisieren.
Ist IMO etwas umständlich, wenn ich jedes Mal unterscheiden muss, ob
der Wert schon da ist oder nicht
Danke und Gruß Christoph
Christoph Engelhardt schrieb:
> So eine "convenience"-Methode wie Dictionary.ReplaceOrAdd() gibt es
> wohl nicht - oder?
>
> Ist IMO etwas umst�ndlich, wenn ich jedes Mal unterscheiden muss, ob
> der Wert schon da ist oder nicht
Deshalb ja den Indexer verwenden, wie Du selbst schon geschrieben hattest.
Viele Gr��e
Marvin
> So eine "convenience"-Methode wie Dictionary.ReplaceOrAdd()
> gibt es wohl nicht - oder?
Das Problem ist da, dass Du dann intern abfragen musst,
ob es schon drin ist, was einen Performance-Hit gibt.
Aber es ist kein Problem diese Methode zu bekommen.
Etwa so:
// Erweiterungsmethoden.cs:
//
using System.Collections.Generic;
static class Erweiterungsmethoden
{
/// <summary>Fügt einen Wert <paramref name="wert"/> in
/// das Wörterbuch mit Add ein, wenn er noch nicht vorhanden
/// ist. Ansonsten wird er mit Add eingefügt.</summary>
public static void ReplaceOrAdd<TKey, TValue>(
this Dictionary<TKey, TValue> dictionary, TKey key, TValue value)
{
if (dictionary.ContainsKey(key)) dictionary[key] = value;
else dictionary.Add(key, value);
}
}
_____________
// Form1.cs:
//
private void Form1_Load(object sender, EventArgs e)
{
Dictionary<string, bool> dic = new Dictionary<string, bool>();
dic.ReplaceOrAdd("eins", true);
dic.ReplaceOrAdd("zwei", true);
dic.ReplaceOrAdd("eins", true);
dic.ReplaceOrAdd("zwei", true);
}
_____________
Unter .NET 2.0 siehe ggf.:
[Using Extension Methods in .NET 2.0 with Visual Studio 2008]
http://geekswithblogs.net/robp/archive/2007/12/20/using-extension-methods-in-.net-2.0-with-visual-studio-2008.aspx
static class Erweiterungsmethoden
{
/// <summary>Fügt einen Wert <paramref name="value"/> mit dem
/// Schlüssel <paramref name="key"/> in das Wörterbuch mit Add ein,
/// wenn der <paramref name="key"/> noch nicht vorhanden war.
/// <para></para>
/// Ansonsten wird er über den Indexer direkt dem zugehörigen
/// <paramref name="key"/> zugewiesen.</summary>
public static void ReplaceOrAdd<TKey, TValue>(
this Dictionary<TKey, TValue> dictionary, TKey key, TValue value)
{
if (dictionary.ContainsKey(key)) dictionary[key] = value;
else dictionary.Add(key, value);
}
}
> Ist IMO etwas umst�ndlich, wenn ich jedes Mal unterscheiden muss, ob
> der Wert schon da ist oder nicht
Die anderen haben Dir zwar schon geantwortet, aber ich bin mir nicht
sicher, ob es klar geworden ist:
Der Indexer
dict[key] = value
leistet genau das. Wenn der Key noch nicht vorhanden ist, tut er das
gleiche wie Add(). Andernfalls wird alte Wert durch den neuen ersetzt.
--
Immo Landwerth
FrankDzaebel schrieb:
> public static void ReplaceOrAdd<TKey, TValue>(
> this Dictionary<TKey, TValue> dictionary, TKey key, TValue value)
> {
> if (dictionary.ContainsKey(key)) dictionary[key] = value;
> else dictionary.Add(key, value);
> }
Was soll denn das bringen, au�er schlechterer Performance?
Der Reflector zumindest sagt mir:
public void set_Item(TKey key, TValue value)
{
this.Insert(key, value, false);
}
public void Add(TKey key, TValue value)
{
this.Insert(key, value, true);
}
Sie unterscheiden sich also nur im dritten Parameter, der nur in dem
Fall ausgewertet wird, dass der Schl�ssel bereit enthalten ist (Insert
pr�ft darauf), und dann ggf. eben die Ausnahme ausl�st:
if (add)
{
ThrowHelper.ThrowArgumentException(
ExceptionResource.Argument_AddingDuplicate
);
}
Wenn der Schl�ssel aber noch nicht enthalten ist, wird der Parameter
ohnehin komplett ignoriert.
Die einzige �nderung ist somit die zus�tzliche Einf�hrung des
ContainsKey-Aufrufs, der Performance kostet.
Viele Gr��e
Marvin
> Der Indexer
> dict[key] = value
> leistet genau das.
Sehe ich genauso.
Intern macht das natürlich nicht nur
Remove und Add sondern einiges mehr
(Validierung, try-catch-Semantik etc.)
Aber die Aufgabe, die Christoph gelöst haben will,
ist über den Indexer zu lösen, da stimme ich voll zu.
ich gebe Dir vollkommen Recht.
Ich hatte auch fälschlich angenommen, Christoph
wollte ein Beispiel für eine "eigene" Dictionary.ReplaceOrAdd
Methode. Das Ziel war aber ja nur, die Abfrage
vorher zu vermeiden, was ja, wie wir alle schon
gepostet hatten, mit dem Indexer am einfachsten
(und auch am performantesten) geht.
Danke an alle für die Antworten.
C# ist doch irgendwie etwas anders als Java :-)