Использование:

тируюUNION способ слияния со словарями (типа Dictionary). Он отлично работает с типом TValue - string, int или даже object. Но если тип TValue является коллекцией (протестировано с List и object []), генерируется исключение:«ArgumentException: элемент с таким же ключом уже был добавлен».

Вот мой код:

Dictionary<int,string> _dico1 = new Dictionary<int, string>()
{
    {0, "zero"},
    {1, "one"}
};

Dictionary<int,string> _dico2 = new Dictionary<int,string>()
{
    {1 , "one"},
    {2 , "two"},
    {3 , "three"},
    {4 , "four"},
    {5 , "five"},
    {6 , "six"}
};

Dictionary<int, List<string>> _dico3 = new Dictionary<int, List<string>>()
{
    {0, new List<string>{"zero"}},
    {1, new List<string>{"one"}}
};

Dictionary<int, List<string>> _dico4 = new Dictionary<int, List<string>>()
{
    {1, new List<string>{"one"}},
    {2, new List<string>{"two"}},
    {3, new List<string>{"three"}},
    {4, new List<string>{"four"}},
    {5, new List<string>{"five"}},
    {6, new List<string>{"six"}},
};

    // works fine
    var mergeDico = _dico1.Union(_dico2).ToDictionary(key => key.Key, value => value.Value);

    // throw an ArgumentException : An item with the same key has already been added
    var mergeDico2 = _dico3.Union(_dico4).ToDictionary(key => key.Key, value => value.Value);

Почему поведение не то же самое? И как решить эту проблему?

Спасибо !

Ответы на вопрос(3)

IEqualityComparer решить вышеуказанную проблему. Вот код, как это можно сделать:

IEqualityComparer:

public class MyEqualityComparer : IEqualityComparer<KeyValuePair<int,List<string>>>
{
    public bool Equals(KeyValuePair<int, List<string>> x, KeyValuePair<int, List<string>> y)
    {
        //Let's say we are comparing the keys only.
        return x.Key == y.Key;
    }

    public int GetHashCode(KeyValuePair<int, List<string>> obj)
    {
        return obj.Key.GetHashCode();
    }
}

Использование:

Dictionary<int, List<string>> _dico3 = new Dictionary<int, List<string>>()
    {
        {0, new List<string> {"zero"}},
        {1, new List<string> {"one"}}
    };

Dictionary<int, List<string>> _dico4 = new Dictionary<int, List<string>>()
    {
        {1, new List<string> {"one"}},
        {2, new List<string> {"two"}},
        {3, new List<string> {"three"}},
        {4, new List<string> {"four"}},
        {5, new List<string> {"five"}},
        {6, new List<string> {"six"}},
    };

Dictionary<int, List<string>> mergeDico2 = _dico3.Union(_dico4, new MyEqualityComparer())
    .ToDictionary(x => x.Key, x => x.Value);
Решение Вопроса

потому что сами пары ключ / значение равны. Во втором случае это не так, потому чтоList<String>{"one"} не равно другомуList<string>{"one"}.

Я подозреваю, что вы хотите, чтобы вашUnion позвонить, чтобы использоватьIEqualityComparer который учитывает только ключи в словаре.

 Jon Skeet25 янв. 2011 г., 10:52
@Florian: Это напрямую не связано с неизменностью, а связано с тем, имеют ли участвующие типы семантику равенства значений. У вас все еще могут быть неизменные типы, которые этого не делают.
 Florian25 янв. 2011 г., 10:52
Итак, в первом случае это работает, потому что тип TValue является типом значения (int) или неизменяемым типом (строка), а во втором случае происходит сбой, потому что TValue является ссылочным типом?


var mergeDico2 = _dico3
    .Concat(_dico4)
    .GroupBy(_=> _.Key, _ => _.Value)
    .ToDictionary(
        group => group.Key,
        group => group.SelectMany(_ => _).ToList());

Он создаст новый словарь, в котором каждое значение является результатом объединения списков из значений обоих словарей. Если вам нужны только отдельные элементы списков, вы можете изменить вызов ToDictionary на этот:


var mergeDico2 = _dico3
    .Concat(_dico4)
    .GroupBy(_=> _.Key, _ => _.Value)
    .ToDictionary(
        group => group.Key,
        group => group.SelectMany(_ => _).Distinct().ToList());

Ваш ответ на вопрос