2010-03-13 4 views
5

Я эксперт на C++, но совсем не для C#. Я создал Dictionary<string, STATS>, где STATS - это простой struct. Когда я построил словарь с начальными string и STATS парами, я хочу изменить значение словаря STATS. В C++, это очень ясно:Изменение значения словаря C#

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

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

Однако, я пытался, как это в 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. 
} 

Это действительно начинающий проблема, но не так легко найти ответ.

EDIT: Я также попытался, как в следующем:

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

Однако я получил исключение, поскольку такое действие аннулирует Словарь:

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

Ух, вы должны были оставить эти заглавные буквы в мире C++. Это выглядит ужасно на C#. Принципы именования Microsoft предлагают использовать случай Pascal. –

+0

Структура - это тип значения, таким образом, это то же самое, что и объявление локального двойника, поэтому новый stat_item является копией словарной записи. Если STATS будет классом, то это будет ссылкой, и тогда это сработает. – weismat

+0

Это очень простая программа для разбора игрушек. : D На самом деле, я все еще люблю писать код в стиле Windows C++, но теперь я вынужден следовать рекомендациям Google ... Извините за это! – minjang

ответ

10

Если ваш STATS действительно struct, это означает, что это тип значение, поэтому там, где вы это делаете:

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

Ваш stat_item является копия значения, расположенного по адресу benchmarks[item.Key]. Таким образом, когда вы передаете его как параметр ref в ParseOutputFile, изменяется только копия .

В коде C++, который вы опубликовали, обратите внимание, что вы сделаете то, что вы пытаетесь выполнить здесь, указав указатель.

Для .NET, решение простое: изменение STATS к ссылочного типаclass, а не struct). Тогда ваша локальная переменная stat_item будет ссылкой на тот же объект, на который ссылается значение benchmarks[item.Key].

+0

Спасибо, это просто хорошо работает. Я не знал этой семантики. – minjang

0

Попробуйте это:

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

Обратите внимание, что даже если STATS является классом, то обновление ссылка (как подразумевается ключевым словом ref) будет обновлять только локальную ссылку stat_item, а не значение в словаре.

Например, следующий код будет изменять значение в словаре, если STATS класс (но в этом случае ссылка ключевое слово не нужны и должны быть удалены):

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

Но следующее завещание влияет только на локальную переменную и не будет обновлять значение словаря, даже если STATS класс:

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

Вы должны просто изменить СТАТЫ в класс. Тогда вам не понадобится ключевое слово ref, и объект изменится.

Обычный совет в C# заключается в использовании классов, если вы абсолютно не уверены, что вы необходимо a struct.

+0

Спасибо за указание! – minjang

Смежные вопросы