Я - эксперт C++, но нисколько для C#. Я создал a 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
Если ваш 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]
.
Просто замените STATS на класс. Тогда вам не понадобится ключевое слово ref, и объект изменится.
Обычный совет в C # - использовать классы, если вы не уверены, что вам нужна структура.
Попробуйте так:
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();
...
}