2010-03-13 28 views
5

Soy un experto en C++, pero no en absoluto para C#. Creé un Dictionary<string, STATS>, donde STATS es un simple struct. Una vez que construí el diccionario con los pares iniciales string y STATS, deseo modificar el valor del STATS del diccionario. En C++, es muy claro:Modificar el valor del diccionario C#

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

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

Sin embargo, he intentado como este en 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. 
} 

Este es un problema muy novato, pero no era fácil encontrar una respuesta.

EDITAR: Yo también trató como la siguiente:

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

Sin embargo, tengo la excepción, ya que tal acción invalida Diccionario:

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

Uf, deberías haber dejado esas letras mayúsculas atrás en el mundo de C++. Se ve horrible en C#. Las pautas de nombres de Microsoft sugieren usar el caso Pascal. –

+0

Una estructura es un tipo de valor, por lo tanto, esto es lo mismo que declarar un doble local, por lo tanto, el nuevo stat_item es una copia del registro del diccionario. Si STATS fuera una clase, entonces es una referencia y luego funcionaría. – weismat

+0

Este es un programa de análisis de juguetes muy simple. : D En realidad, todavía me encanta escribir código en el estilo de Windows C++, pero ahora estoy obligado a seguir las directrices de Google ... ¡Lo siento por eso! – minjang

Respuesta

10

Si su STATS es de hecho un struct, que significa que es un valor de tipo , por lo que cuando usted hace esto:

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

Su stat_item es una copia del valor situado en benchmarks[item.Key]. Por lo tanto, cuando lo pasa como un parámetro ref a ParseOutputFile, solo se modifica la copia .

En el código de C++ que publicó, observe que haría aquí lo que está intentando lograr utilizando un puntero.

para .NET, la solución es simple: cambio STATS a un tipo referencia (a class en lugar de struct). Entonces su variable stat_item local será una referencia al mismo objeto al que hace referencia el valor de benchmarks[item.Key].

+0

Gracias, simplemente funciona bien. No sabía que tal semántica. – minjang

0

Prueba esto:

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

Tenga en cuenta que incluso si STATS es una clase, entonces la actualización la referencia (como lo implica la palabra clave ref) solo actualizará la referencia local stat_item, no el valor en el diccionario.

Por ejemplo, el siguiente código modificará el valor en el diccionario Si la estadística es una clase (pero en este caso no es necesaria la palabra clave ref y deben ser eliminados):

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

Pero la siguiente voluntad sólo afectan a la variable local y no se actualizará el valor del diccionario, incluso si es una clase STATS:

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

Solo debe cambiar STATS a una clase. Entonces no necesitarías la palabra clave ref y el objeto cambiaría.

El consejo habitual en C# es utilizar clases a menos que esté absolutamente seguro de que necesita a struct.

+0

¡Gracias por señalar! – minjang

Cuestiones relacionadas