Как изменить значение по ключу в словаре Dictionary в C#?
Прямое присвоение значения по ключу
Самый простой способ обновить значение в Dictionary — использовать индексатор:
scores["Bob"] = 250;
Этот метод работает, только если ключ уже существует в словаре. Если ключа нет, вы получите исключение KeyNotFoundException. Поэтому такой подход подходит, когда вы точно уверены, что ключ присутствует.
Безопасное обновление с проверкой через TryGetValue
Для безопасного обновления значения, когда вы не уверены в наличии ключа, используйте метод TryGetValue:
if (scores.TryGetValue("Bob", out int currentScore))
{
scores["Bob"] = currentScore + 50; // Обновляем только если ключ существует
}
else
{
Console.WriteLine("Ключ не найден");
}
Этот подход гарантирует, что вы не получите исключение, и позволяет выполнить логику только при наличии ключа.
Метод ContainsKey + индексатор
Альтернативный вариант — сначала проверить существование ключа через ContainsKey:
if (scores.ContainsKey("Bob"))
{
scores["Bob"] = 250;
}
Однако этот метод менее эффективен, так как выполняет два поиска в словаре (один для проверки, второй для присвоения). Для большинства случаев разница незначительна, но в высоконагруженных приложениях лучше использовать TryGetValue.
Обновление с добавлением, если ключ отсутствует
Если вы хотите обновить значение, а если ключа нет — добавить новую пару, используйте индексатор напрямую:
scores["David"] = 300; // Если ключа нет, он будет создан
Индексатор Dictionary работает по принципу "взять или создать": если ключ существует — обновляет значение, если нет — добавляет новую пару.
Метод TryAdd (C# 7.0+)
Если вы хотите только добавить значение, но не обновлять существующее, используйте TryAdd:
bool added = scores.TryAdd("Bob", 300); // Вернет false, так как ключ уже существует
// Значение Bob останется 200
Этот метод полезен, когда нужно гарантировать, что существующие данные не будут перезаписаны.
Продвинутый подход: использование LINQ (не рекомендуется)
Хотя технически можно использовать LINQ для обновления, это неэффективно и не стоит того:
var key = scores.FirstOrDefault(kvp => kvp.Key == "Bob").Key;
if (key != null) scores[key] = 250;
Избегайте этого подхода — он медленнее и менее читаем.
Рекомендация для вашего случая
Для обновления баллов пользователя "Bob" используйте проверку через TryGetValue, так как вы не уверены в наличии ключа:
if (scores.TryGetValue("Bob", out int currentScore))
{
scores["Bob"] = currentScore + 50;
Console.WriteLine($"Баллы Bob обновлены: {scores["Bob"]}");
}
else
{
Console.WriteLine("Пользователь Bob не найден");
}
Этот код безопасен, эффективен и легко читается.
Полный пример с обработкой
Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "Alice", 150 },
{ "Bob", 200 },
{ "Charlie", 175 }
};
string targetUser = "Bob";
int increment = 50;
if (scores.TryGetValue(targetUser, out int oldScore))
{
scores[targetUser] = oldScore + increment;
Console.WriteLine($"{targetUser}: {oldScore} → {scores[targetUser]}");
}
else
{
Console.WriteLine($"Пользователь {targetUser} не найден");
}
<<Использование ConcurrentDictionary для многопоточности
Если ваше приложение работает в многопоточной среде, стандартный Dictionary не является потокобезопасным. В таких случаях используйте ConcurrentDictionary из пространства имен System.Collections.Concurrent:
using System.Collections.Concurrent;
ConcurrentDictionary<string, int> scores = new ConcurrentDictionary<string, int>();
scores.TryAdd("Bob", 200);
// Безопасное обновление в многопоточном контексте
scores.AddOrUpdate("Bob",
addValue: 250, // Значение, если ключа нет
updateValueFactory: (key, oldValue) => oldValue + 50); // Функция обновления
Метод AddOrUpdate атомарно выполняет операцию: если ключа нет — добавляет новое значение, если есть — применяет функцию обновления. Это идеально подходит для сценариев, где несколько потоков могут одновременно пытаться изменить один и тот же ключ.
Для простого однопоточного приложения стандартный Dictionary с проверкой TryGetValue будет наиболее оптимальным решением.