【问题标题】:Swap Key and Value in Concurrent Dictionary in C#在 C# 中交换并发字典中的键和值
【发布时间】:2019-11-16 01:34:49
【问题描述】:

有没有办法在 C# 的并发字典中交换键和值?我知道Dictionary 类型,它可能类似于

dictionary = dictionary.ToDictionary(x => x.Value, x => x.Key);

ConcurrentDictionary 有什么类似的吗?

【问题讨论】:

  • ConcurrentDictionary 所做的只是在添加/删除/访问操作周围添加一些锁。还有 coruse MT 独有的东西,比如 TryAdd 和 TryUpdate - 也有锁。
  • 您想在ConcurrentDictionary 被多个线程主动更新时进行此交换吗?如果是,那么您可能希望在进行交换之前拍摄ConcurrentDictionary 中包含的数据的快照,而不是混合使用新旧条目。要拍摄快照,您需要使用它的方法ToArray。不要使用 LINQ 方法 (reference)。
  • 注意:上面的警告特定于ConcurrentDictionary 类。其他并发容器,例如 ConcurrentQueue,可以安全地与 LINQ 一起使用,因为它们的 GetEnumerator 方法使用数据的快照。 (citation)
  • @Christopher 所以如果我所做的只是对字典的读取权限,是否需要使用并发字典?
  • 如果您使用来自多个任务/线程的同一个实例,您将使用并发类 - 或您自己的锁定机制。您没有向我们展示几乎足够的答案。最后,只有代码前面的人才能防止竞争条件。

标签: c# dictionary concurrency keyvaluepair


【解决方案1】:

您不能直接将 Dictionary 转换或转换为 ConcurrentDictionary。 购买你可以创建一个带有字典的 ConcurrentDictionary,检查这个构造函数

public ConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection);

再看看你说的LINQ的扩展方法

  public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector,
        Func<TSource, TElement> elementSelector);

所以如果DictionaryIEnumerable&lt;KeyValuePair&lt;TKey, TValue&gt;&gt; 兼容

解决方案 1

只需使用 LINQ 的 ToDictionary 扩展方法

var concurrentDict = new ConcurrentDictionary<string, string>();
/* Add some items */
bool firstItem = concurrentDict.TryAdd("1", "First");  //returns true
bool secondItem = concurrentDict.TryAdd("2", "Second");  //returns  true

/* Swaping Value <-> Key to new Dictionary */
Dictionary<string,string> normalDict = concurrentDict.ToDictionary(x => x.Value, x => x.Key);

/* creating ConcurrentDictionary */
var newConcurrentDict = new ConcurrentDictionary<string, string>(normalDict);

解决方案 2

线程安全呢?

您可以使用自定义扩展方法(如 LINQ)

var concurrentDict = new ConcurrentDictionary<string, string>();
/* Add some items */
bool firstItem = concurrentDict.TryAdd("1", "First");  //returns true
bool secondItem = concurrentDict.TryAdd("2", "Second");  //returns  true

/* Swaping Value <-> Key to new Dictionary */
Dictionary<string,string> normalDict = concurrentDict.ToDictionary(x => x.Value, x => x.Key);

/* creating ConcurrentDictionary */
var newConcurrentDict = normalDict.ToConcurrentDictionary();

扩展方法

参考https://stackoverflow.com/a/27064366/1669574

public static class ConcurrentDictionaryExtensions
{
    public static ConcurrentDictionary<TKey, TElement> ToConcurrentDictionary<TSource, TKey, TElement>(
        this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector,
        IEqualityComparer<TKey> comparer)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (keySelector == null) throw new ArgumentNullException("keySelector");
        if (elementSelector == null) throw new ArgumentNullException("elementSelector");

        ConcurrentDictionary<TKey, TElement> d = new ConcurrentDictionary<TKey, TElement>(comparer);
        foreach (TSource element in source)
            d.TryAdd(keySelector(element), elementSelector(element));

        return d;
    }

    public static ConcurrentDictionary<TKey, TSource> ToConcurrentDictionary<TSource, TKey>(
        this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
    {
        return ToConcurrentDictionary<TSource, TKey, TSource>(source, keySelector, IdentityFunction<TSource>.Instance,
            null);
    }

    public static ConcurrentDictionary<TKey, TSource> ToConcurrentDictionary<TSource, TKey>(
        this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
    {
        return ToConcurrentDictionary<TSource, TKey, TSource>(source, keySelector, IdentityFunction<TSource>.Instance,
            comparer);
    }

    public static ConcurrentDictionary<TKey, TElement> ToConcurrentDictionary<TSource, TKey, TElement>(
        this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
    {
        return ToConcurrentDictionary<TSource, TKey, TElement>(source, keySelector, elementSelector, null);
    }

    internal class IdentityFunction<TElement>
    {
        public static Func<TElement, TElement> Instance
        {
            get { return x => x; }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-08
    • 1970-01-01
    相关资源
    最近更新 更多