c# dictionary用法 - 在Dictionary中添加新的或更新现有项目的方法




dictionary遍历 dictionary排序 (5)

在一些遗留代码中,我已经看到以下扩展方法,以便于添加新的键值项或更新值(如果键已经存在)。

方法-1(遗留代码)。

public static void CreateNewOrUpdateExisting<TKey, TValue>(
    this IDictionary<TKey, TValue> map, TKey key, TValue value)
{            
    if (map.ContainsKey(key))
    {
        map[key] = value;
    }
    else
    {
        map.Add(key, value);
    }
}

虽然,我已经检查过map[key]=value是否完全一样的工作。 也就是说,这种方法可以用下面的方法-2代替。

方法2。

public static void CreateNewOrUpdateExisting<TKey, TValue>(
    this IDictionary<TKey, TValue> map, TKey key, TValue value)
{
    map[key] = value;
}

现在,我的问题是..如果我用Method-2替换Method-1,会不会有问题? 它会在任何可能的情况下破裂吗?

另外,我认为这曾经是HashTable和Dictionary之间的区别。 HashTable允许更新一个项目,或者使用索引器添加一个新项目,而Dictionary不会! 这种差异在C#> 3.0版本中被消除了吗?

如果用户再次发送相同的键值,则此方法的目标不会太抛出异常,方法应该只更新具有新值的条目,并且如果已将新键值对发送到方法,则创建新条目。


Answers

在功能上,它们是等效的。

性能明智的map[key] = value会更快,因为您只是进行单一查找而不是两次。

风格明智,越短越好:)

在大多数情况下,代码似乎在多线程上下文中工作正常。 但是,如果没有额外的同步,它不是线程安全的。


这里没有问题。 我甚至会从源代码中删除CreateNewOrUpdateExisting ,并直接在你的代码中使用map[key] = value ,因为这样更具可读性,因为开发人员通常会知道map[key] = value含义。


如果我用Method-2替换Method-1,会不会有问题?

不,只需使用map[key] = value 。 这两个选项是相同的。


关于Dictionary<>Hashtable :当你启动Reflector时,你会发现两个类的索引器setter调用this.Insert(key, value, /* add */ false);add参数负责在插入重复键时抛出异常。 所以这两个类的行为都是一样的。


老问题,但我觉得我应该添加以下内容,甚至更多,因为.NET 4.0已经在问题写入时启动。

从.net 4.0开始,有一个命名空间System.Collections.Concurrent ,它包含线程安全的集合。

System.Collections.Concurrent.ConcurrentDictionary<>集合完全符合你的需求。 它具有AddOrUpdate()方法,并具有线程安全的附加优势。

如果您处于高性能场景,并且不处理多个线程,则已经给出的map[key] = value答案会更快。

在大多数情况下,这种性能优势是微不足道的。 如果是的话,我建议使用ConcurrentDictionary,因为:

  1. 它在框架中 - 它经过了更多的测试,你不是必须维护代码的人
  2. 它是可扩展的:如果你切换到多线程,你的代码已经为它准备好了

由于异常发生在Dictionary代码内部,这意味着您同时从多个线程访问同一个Dictionary实例。

您需要同步GetInstance方法中的代码,以便一次只有一个线程访问Dictionary

编辑:
单独锁定访问,以便在执行(假设)耗时的加载时不在锁内:

private static object _sync = new object();

public static object GetInstance(string key) {
   object instance = null;
   bool found;
   lock (_sync) {
      found = Instances.TryGetValue(key, out instance);
   }
   if (!found) {
      instance = LoadInstance(key);
      lock (_sync) {
         object current;
         if (Instances.TryGetValue(key, out current)) {
            // some other thread already loaded the object, so we use that instead
            instance = current;
         } else {
            Instances[key] = instance;
         }
      }
   }
   return instance;
}




c# dictionary