Проблема с обновлением содержимого словаря в цикле foreach - PullRequest
2 голосов
/ 16 июля 2010

Я пишу простое расширение общего обновления для IEnumerable, этот метод используется для объединения заданного 2 списка бизнес-объектов или словарей с использованием заданных ключей и обновления определенного поля.

public static void Update<TOuter, TInner, TKey>(this IEnumerable<TOuter> outer, IEnumerable<TInner> Inner, Func<TOuter, TKey> OuterKeySelector, Func<TInner, TKey> InnerKeySelector,Action<TOuter,TInner> updator)
        {
            ILookup<TKey, TInner> innerLookup = Inner.ToLookup(InnerKeySelector, element => element);

            foreach (TOuter outerItem in outer)
            {
                TKey key = OuterKeySelector(outerItem);
                if (innerLookup.Contains(key))
                {
                    foreach (TInner innerItem in innerLookup[key])
                    {
                        updator(outerItem, innerItem);
                    }
                }
            }

        }

Это прекрасно работает вобычные объекты, например:

      List<testObject> obj1 = new List<testObject>()
       {
           new testObject(){fruitId=1,name="mango"},
           new testObject(){fruitId=2,name="grapes"},
           new testObject(){fruitId=2,name="grapes"},
           new testObject(){fruitId=4,name="kivi"},
       };

       List<testObject> obj2 = new List<testObject>()
       {
           new testObject(){fruitId=2,name="apple"},
           new testObject(){fruitId=4,name="orange"},
       };

        obj1.Update(obj2,
             tx => tx.fruitId,
             ty => ty.fruitId,
            (tx,ty)=>tx.name=ty.name);

Но я не могу использовать этот метод со словарем,

       Dictionary<string, int> first = new Dictionary<string, int>()
       {
           {"a",1},
           {"b",2},
           {"c",9},
           {"e",5},               
       };
       Dictionary<string, int> second = new Dictionary<string, int>()
        {
           {"a",8},
           {"b",2},
           {"e",20}               
       };
       var kk = 0;

       first.Update(second,
           f1 => f1.Key,
           s1 => s1.Key,
           (f1, s1) => f1.Value = s1.Value);

, он дает следующую ошибку

Свойство илииндексатор 'System.Collections.Generic.KeyValuePair.Value' не может быть назначен - он доступен только для чтения

Я знаю, что для MSDN

перечислители есть ограничениеможет использоваться для чтения данных в коллекции, но они не могут использоваться для изменения базовой коллекции.

Есть ли хак / обходной путь для достижения той же функциональности в общем виде?

Ответы [ 3 ]

2 голосов
/ 16 июля 2010

Ваш код кажется разумным, если вы смотрите его таким же образом для List, что и для Dictionary.

В вашем примере списка у вас есть List<MyMutableType>, и вы обновляете PropertyMyMutableType объект в определенной позиции в списке.

В вашем примере словаря у вас есть Dictionary<Key,MyNotMutableType>, и вы пытаетесь заменить экземпляр MyNotMutableType в определенной позиции другим экземпляром MyNotMutableType, вы 'мы не пытаемся просто изменить Property того же экземпляра объекта.

Следуя подходу, используемому для List, у вас должен быть словарь, подобный: Dictionary<Key,MyMutableType>, а в делегате вашего средства обновления вы должны обновлять только свойствоthe MyMutableType.

Надеюсь, что эта помощь (и извините за мой плохой английский)

1 голос
/ 16 июля 2010

Еще один способ решить эту проблему - переключить ваши внутренние и внешние классы.Класс, который должен быть обновлен, должен быть внутренним, так что это не позволяет изменяемой коллекции войти в перечисление.

1 голос
/ 16 июля 2010

Ошибка, которую вы получаете не из-за невозможности изменить словарь при перечислении коллекции, это ошибка времени выполнения. Как говорится в сообщении об ошибке, KeyValuePair не имеет установщика для параметра Value. поэтому f1.Value == s1.Value не допускается. По сути, KeyValuePair является неизменным, так как вы не можете изменить значения.

Если вы хотите использовать этот тип функциональности, я бы порекомендовал вам создать более конкретное обновление, которое использует словарь, а не IEnumerable.

С точки зрения обхода того факта, что словари читаются только при перечислении, я не знаю ответа.

...