Как преобразовать словарь в ConcurrentDictionary?

Я видел, как преобразовать ConcurrentDictionary в словарь, но у меня есть словарь, и я хотел бы преобразовать его в ConcurrentDictionary. Как мне это сделать?... еще лучше, могу ли я установить оператор ссылки как ConcurrentDictionary?

var customers = _customerRepo.Query().Select().ToDictionary(x => x.id, x => x);

person MrM    schedule 21.11.2014    source источник
comment
Какой поставщик LINQ вы используете? Является ли результат Query() или Select() IQueryable или IEnumerable?   -  person Panagiotis Kanavos    schedule 21.11.2014


Ответы (4)


Используйте ConcurrentDictionary<TKey, TValue> Constructor (IEnumerable<KeyValuePair<TKey, TValue>>) конструктор, который может принимать объект словаря, например:

Dictionary<int, string> dictionary = new Dictionary<int, string>();
dictionary.Add(1,"A");
dictionary.Add(2, "B");

ConcurrentDictionary<int,string> concurrentDictionary = 
             new ConcurrentDictionary<int, string>(dictionary);

Могу ли я установить оператор LINQ как ConcurrentDictionary?

Нет. Нельзя.. Нет доступного метода расширения для создания ConcurrentDictionary в LINQ. Вы можете либо создать свой собственный метод расширения, либо использовать конструктор ConcurrentDictionary в своем запросе LINQ при проецировании результатов.

person Habib    schedule 21.11.2014
comment
Что ж, вы можете спроецировать результаты в словарь с помощью LINQ, но для этого вам придется написать собственный метод расширения ToConcurrentDictionary. (Возможно, вы сможете избавиться от промежуточного словаря и вставить напрямую, используя foreach и приняв делегат селектора ключа и значения). - person Scott Chamberlain; 21.11.2014
comment
Вы можете использовать LINQ с упомянутым вами конструктором. Создайте KeyValuePair из исходного перечисления с нужным ключом и значениями, затем передайте его конструктору, например. myEnumerable= ... Select(item=>new KeyValuePair(item.Id,item); ... new ConcurrentDictionary(myEnumerable);. Нет необходимости в ForEach, хотя метод расширения сделал бы код немного чище. - person Panagiotis Kanavos; 21.11.2014

Почему бы не написать собственный метод расширения:

  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 ?? EqualityComparer<TKey>.Default);
        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; }
        }
    }

}

Просто взял код из .Net framework< /а>.

person Oliver    schedule 21.11.2014
comment
@MotKohn: Ты прав. Исправлен код согласно источнику. - person Oliver; 22.09.2020

Оператор LINQ-To-Objects в конечном итоге является IEnumerable, поэтому вы можете передать его конструктору ConcurrentDictionary, например:

var customers = myCustomers.Select(x => new KeyValuePair(x.id, x));
var dictionary=new ConcurrentDictionary(customers);

Это может не работать с другими провайдерами. Linq to Entities, например, преобразует всю инструкцию LINQ в SQL и не может проецировать на KeyValuePair. В этом случае вам, возможно, придется вызвать AsEnumerable() или любой другой метод, который заставляет IQueryable выполняться, например:

var customers = _customerRepo.Customers.Where(...)
                             .AsEnumerable()
                             .Select(x => new KeyValuePair(x.id, x));
var dictionary=new ConcurrentDictionary(customers);

Select() без аргументов не является методом IEnumerable или IQueryable, поэтому я полагаю, что это метод, предоставляемый какой-то другой ORM. Если Select() возвращает IEnumerable, вы можете использовать первый вариант, иначе вы можете использовать AsEnumerable()

person Panagiotis Kanavos    schedule 21.11.2014
comment
Обратите внимание, что вы можете выполнить AsEnumerable() для перечисляемого и это ничему не повредит. - person Scott Chamberlain; 21.11.2014

Или просто иметь метод:

 private ConcurrentDictionary<TKey, TValue> ToConcurrent<TKey, TValue>(Dictionary<TKey, TValue> dic) {
        return new ConcurrentDictionary<TKey, TValue>(dic);
    }

а затем выполните:

var customers = _customerRepo.Query().Select().ToDictionary(x => x.id, x => x);
var concurrentDic = ToConcurrent(customers);

Лично я использую метод расширения, который я только что обновил...

person Denis    schedule 15.03.2016