开发者

Problem Updating the the contents of Dictionary in foreach loop

I am writing a simple generic update extension for IEnumerable, this method used to join given 2 List of business objects or dictionaries using the given keys and updating the specific field.

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);
                    }
                }
            }

        }

This works fine in normal objects, for ex:

      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);

But, i cannot use this method with dictionary,

       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);

it gives the below error

Property or indexer 'System.Collections.Generic.KeyValuePair.Value' cannot be assigned to -- it is read only

I know there is a restriction, by MSDN

Enumerators can be used to read the data in the collection, but they cannot be used to modify the underlyi开发者_运维知识库ng collection.

is there a hack/workaround to achive the same functionality in a generic manner?


Your code seems reasonable if you look it in the same manner for List as for Dictionary.

In your list example you have a List<MyMutableType> and you update a Property of the MyMutableType object in a certain position in the list.

In your dictionary example you have a Dictionary<Key,MyNotMutableType> and you are trying to substitute a MyNotMutableType instance in a certain position with another MyNotMutableType instance, you're not trying to simply change a Property of the same object instance.

Following the approach used for List you should have a dictionary like: Dictionary<Key,MyMutableType> and in your updater delegate you should only update a Property of the MyMutableType.

Hope this help (and sorry for my poor english)


The error you are getting is not because of the inability to modify the dictionary while you are enumerating a collection, this is a runtime error. It is, as the error says, that the KeyValuePair does not have a setter on the Value parameter. so f1.Value == s1.Value is not allowed. Essentially KeyValuePair is immutable as you can't change the values.

If you want this type of functionality I would recommend that you create a more specific Update that takes a Dictionary specifically rather than a IEnumerable.

In terms of working around the fact that dictionaries are readonly when the are being enumerated I don't know an answer.


Another way to solve this problem is to switch your inner & outer classes. Class that needs to be updated should be inner, so this avoids the modiable collection to enter into the enumuration..

       second.Update(first1,
           s1 => s1.Key,
           f1 => f1.Key,   
          (f1, s1) => first1[s1.Key] = f1.Value);

Thanks andyp & digEmAll

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜