2010-03-13 2 views
5

Sono un esperto in C++, ma non per C#. Ho creato uno Dictionary<string, STATS>, dove STATS è un semplice struct. Una volta creato il dizionario con le coppie iniziali string e STATS, desidero modificare il valore STATS del dizionario. In C++, è molto chiaro:Modifica valore dizionario C#

Dictionary<string, STATS*> benchmarks; 
Initialize it... 

STATS* stats = benchmarks[item.Key]; 
// Touch stats directly 

Tuttavia, ho provato come questo in C#:

Dictionary<string, STATS> benchmarks = new Dictionary<string, STATS>(); 

// Initialize benchmarks with a bunch of STATS 
foreach (var item in _data) 
    benchmarks.Add(item.app_name, item); 

foreach (KeyValuePair<string, STATS> item in benchmarks) 
{ 
    // I want to modify STATS value inside of benchmarks dictionary. 
    STATS stat_item = benchmarks[item.Key]; 
    ParseOutputFile("foo", ref stat_item); 

    // But, not modified in benchmarks... stat_item is just a copy. 
} 

Questo è un problema davvero alle prime armi, ma non è stato facile trovare una risposta.

EDIT: Ho anche provato come il seguente:

STATS stat_item = benchmarks[item.Key]; 
    ParseOutputFile(file_name, ref stat_item); 
    benchmarks[item.Key] = stat_item; 

Tuttavia, ho avuto l'eccezione in quanto tale azione invalida Dizionario:

Unhandled Exception: System.InvalidOperationException: Collection was modified; enumeration operation may not execute. 
    at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) 
    at System.Collections.Generic.Dictionary`2.Enumerator.MoveNext() 
    at helper.Program.Main(String[] args) in D:\dev\\helper\Program.cs:line 75 
+4

Ugh, dovresti aver lasciato quelle lettere maiuscole nel mondo C++. Sembra orribile in C#. Le linee guida per la denominazione di Microsoft suggeriscono di utilizzare il caso Pascal. –

+0

Una struct è un tipo di valore, quindi questo è lo stesso, quindi dichiara un double locale, quindi il nuovo stat_item è una copia del record del dizionario. Se STATS fosse una classe, allora è un riferimento e quindi funzionerebbe. – weismat

+0

Questo è un programma di analisi del giocattolo molto semplice. : D In realtà, mi piace ancora scrivere codice in stile Windows C++, ma ora sono costretto a seguire le linee guida di Google ... Ci scusiamo per questo! – minjang

risposta

10

Se il STATS è davvero un struct, che significa che è un tipo di valore di , quindi dove si esegue questa operazione:

STATS stat_item = benchmarks[item.Key]; 
ParseOutputFile("foo", ref stat_item); 

tuo stat_item è una copia del valore situato a benchmarks[item.Key]. Pertanto, quando lo si passa come parametro ref a ParseOutputFile, viene modificata solo la copia .

Nel codice C++ postato, si nota che si farebbe ciò che si sta tentando di eseguire qui utilizzando un puntatore.

Per NET, la soluzione è semplice: cambiamento STATS un tipo riferimento (a class anziché struct). Quindi la variabile locale stat_item sarà un riferimento allo stesso oggetto a cui fa riferimento il valore di benchmarks[item.Key].

+0

Grazie, funziona bene. Non sapevo che tale semantica. – minjang

0

Prova questo:

STATS stat_item = benchmarks[item.Key]; 
ParseOutputFile("foo", ref stat_item); 
benchmarks[item.Key] = stat_item; 

Si noti che anche se STAT è una classe, quindi l'aggiornamento il riferimento (come è implicito dalla parola chiave ref) aggiornerà solo il riferimento locale stat_item, non il valore nel dizionario.

Ad esempio, il seguente codice modificherà il valore nel dizionario se STATS è una classe (ma in questo caso non è necessaria la parola chiave ref e dovrebbe essere rimosso):

ParseOutputFile(string foo, ref STATS statItem) 
{ 
    statItem.SomeProperty = ... 
} 

Ma il seguente volontà riguardano solo la variabile locale e non aggiornerà il valore dizionario, anche se STATS è una classe:

ParseOutputFile(string foo, ref STATS statItem) 
{ 
    statItem = new STATS(); 
    ... 
} 
2

Dovresti solo cambiare STATS in una classe. Quindi non avresti bisogno della parola chiave ref e l'oggetto cambierebbe.

Il solito consiglio in C# è di utilizzare le classi a meno che non si sia assolutamente certi che lo abbia bisogno di una struct.

+0

Grazie per il precisissimo! – minjang