Поменять местами ключ и значение в параллельном словаре в С#

Есть ли способ поменять ключ и значение в Concurrent Dictionary на С#? Я знаю, что для типа Dictionary это может быть что-то вроде

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

Что-нибудь подобное в ConcurrentDictionary?


person superninja    schedule 16.11.2019    source источник
comment
Все, что делает ConcurrentDictionary, — это блокирует операции добавления/удаления/доступа. А из coruse MT только штучки, вроде TryAdd и TryUpdate - тоже с блокировками.   -  person Christopher    schedule 16.11.2019
comment
Вы хотите сделать этот обмен, пока ConcurrentDictionary активно обновляется несколькими потоками? Если да, то вы, вероятно, захотите сделать снимок данных, содержащихся в ConcurrentDictionary, перед выполнением свопа, а не использовать сочетание новых и старых записей. Чтобы сделать снимок, вам нужно использовать его метод ToArray. Не используйте методы LINQ (ссылка).   -  person Theodor Zoulias    schedule 16.11.2019
comment
Примечание. Приведенное выше предостережение относится к классу ConcurrentDictionary. Другие параллельные контейнеры, например ConcurrentQueue, можно безопасно использовать с LINQ, поскольку их метод GetEnumerator использует моментальный снимок данных. (цитирование )   -  person Theodor Zoulias    schedule 16.11.2019
comment
@Christopher, так что, если все, что я делаю, это доступ для чтения к словарю, нужно ли использовать параллельный словарь?   -  person superninja    schedule 20.11.2019
comment
Вы используете параллельные классы или свой собственный механизм блокировки, если работаете с одним и тем же экземпляром из нескольких задач/потоков. Вы не показали нам почти достаточно для ответа. В конце концов, только тот, кто стоит перед кодом, может предотвратить состояние гонки.   -  person Christopher    schedule 20.11.2019


Ответы (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);

Итак, если Dictionary совместим с IEnumerable<KeyValuePair<TKey, TValue>>

Решение 1

Просто используйте метод расширения ToDictionary 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 = 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; }
        }
    }
}
person Clystian    schedule 16.11.2019