Изменение значения словаря C # - PullRequest
5 голосов
/ 13 марта 2010

Я эксперт по C ++, но совсем не по C #. Я создал Dictionary<string, STATS>, где STATS - это простое struct. После того как я собрал словарь с исходными парами string и STATS, я хочу изменить значение словаря STATS. В 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.
}

Это действительно новичок, но найти ответ было нелегко.

РЕДАКТИРОВАТЬ : Я также пытался сделать следующее:

  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

Ответы [ 3 ]

10 голосов
/ 13 марта 2010

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

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

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

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

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

2 голосов
/ 13 марта 2010

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

Обычный совет в C # - использовать классы, если вы не уверены, что вам нужна структура.

0 голосов
/ 13 марта 2010

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

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

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

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

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

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

ParseOutputFile(string foo, ref STATS statItem)
{
    statItem = new STATS();
    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...