Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Vollkommen unverständliche Exception

469 views
Skip to first unread message

Christoph Engelhardt

unread,
Nov 11, 2009, 7:03:31 AM11/11/09
to
Servus NG,

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

FrankDzaebel

unread,
Nov 11, 2009, 7:24:51 AM11/11/09
to
Hallo 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

Christoph Engelhardt

unread,
Nov 11, 2009, 8:31:07 AM11/11/09
to

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?

Immo Landwerth

unread,
Nov 11, 2009, 8:45:26 AM11/11/09
to
Christoph Engelhardt wrote:

> 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

FrankDzaebel

unread,
Nov 11, 2009, 8:55:10 AM11/11/09
to
Hallo Christoph,

> > 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.

Christoph Engelhardt

unread,
Nov 11, 2009, 9:23:41 AM11/11/09
to
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

Danke und Gruß Christoph

Marvin Massih

unread,
Nov 11, 2009, 9:46:39 AM11/11/09
to
Hallo 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

FrankDzaebel

unread,
Nov 11, 2009, 9:49:42 AM11/11/09
to
Hallo Christoph,

> 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

FrankDzaebel

unread,
Nov 11, 2009, 9:57:55 AM11/11/09
to
ich habe den <summary> Text nochmal angepasst:

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);
}
}

Immo Landwerth

unread,
Nov 11, 2009, 10:56:48 AM11/11/09
to
Christoph Engelhardt wrote:

> 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

Marvin Massih

unread,
Nov 11, 2009, 11:19:38 AM11/11/09
to
Hallo Frank,

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

FrankDzaebel

unread,
Nov 11, 2009, 11:28:08 AM11/11/09
to
Hallo Christoph und Immo,

> 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.

FrankDzaebel

unread,
Nov 11, 2009, 11:58:56 AM11/11/09
to
Hallo Marvin,

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.

Christoph Engelhardt

unread,
Nov 11, 2009, 1:47:02 PM11/11/09
to

> 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.
>
> ciao Frank

Danke an alle für die Antworten.

C# ist doch irgendwie etwas anders als Java :-)

0 new messages