【问题标题】:Problem Updating the the contents of Dictionary in foreach loop在 foreach 循环中更新字典内容的问题
【发布时间】:2010-07-16 09:39:14
【问题描述】:

我正在为 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 有限制

枚举器可用于读取 集合中的数据,但它们 不能用于修改 基础集合。

是否有以通用方式实现相同功能的 hack/解决方法?

【问题讨论】:

  • 你试过 second[f1.Key] = s1.Value 吗?
  • @andyp,它的第一个[f1.Key] = s1.Value.. 我也试过了.. 但它给出了一个错误“集合已修改;枚举操作可能无法执行。”
  • 如果你真的想这样做,你可以在你的扩展中写foreach (TOuter outerItem in outer.ToList())...
  • @digEmAll,不工作。无论您做什么更改,它仍然返回键值对列表..:)
  • @Ramesh:我的意思是 andyp 解决方案(即second[f1.Key] = s1.Value)加上我的(即扩展中的foreach 修改)。我已经测试过了,它可以工作(即使不是那么优雅)

标签: c# dictionary extension-methods


【解决方案1】:

如果您以与 ListDictionary 相同的方式查看代码,您的代码似乎是合理的。

在您的列表示例中,您有一个 List&lt;MyMutableType&gt;,并且您在列表中的某个位置更新了 MyMutableType 对象的 Property

在您的字典示例中,您有一个 Dictionary&lt;Key,MyNotMutableType&gt; 并且您试图用另一个 MyNotMutableType 实例替换某个位置的 MyNotMutableType 实例,您不是想简单地更改相同的 Property对象实例。

按照用于 List 的方法,您应该有一个字典,例如: Dictionary&lt;Key,MyMutableType&gt; 并且在您的更新程序委托中,您应该只更新 MyMutableType 的属性。

希望对您有所帮助(对于我糟糕的英语感到抱歉)

【讨论】:

    【解决方案2】:

    您遇到的错误不是因为在枚举集合时无法修改字典,这是运行时错误。正如错误所说,KeyValuePair 在 Value 参数上没有设置器。所以 f1.Value == s1.Value 是不允许的。本质上 KeyValuePair 是不可变的,因为您无法更改值。

    如果您想要这种类型的功能,我建议您创建一个更具体的更新,该更新专门采用字典而不是 IEnumerable。

    就解决字典在枚举时为只读这一事实而言,我不知道答案。

    【讨论】:

      【解决方案3】:

      解决此问题的另一种方法是切换内部和外部类。需要更新的类应该是inner的,这样就避免了可修改的集合进入枚举..

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

      谢谢andyp & digEmAll

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-25
        • 1970-01-01
        • 2018-11-10
        • 2012-03-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-03
        相关资源
        最近更新 更多