C# 在foreach循环中更新字典内容时出现问题

C# 在foreach循环中更新字典内容时出现问题,c#,dictionary,extension-methods,C#,Dictionary,Extension Methods,我正在为IEnumerable编写一个简单的通用更新扩展,该方法用于使用给定的键连接给定的2个业务对象或字典列表,并更新特定字段 public static void Update<TOuter, TInner, TKey>(this IEnumerable<TOuter> outer, IEnumerable<TInner> Inner, Func<TOuter, TKey> OuterKeySelector, Func<TInner, T

我正在为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);
                    }
                }
            }

        }
公共静态无效更新(此IEnumerable外部、IEnumerable内部、Func OuterKeySelector、Func InnerKeySelector、Action更新程序)
{
ILookup innerLookup=Inner.ToLookup(InnerKeySelector,element=>element);
foreach(在外部的TOuter outerItem)
{
TKey key=OuterKeySelector(outerItem);
if(innerLookup.Contains(键))
{
foreach(innerLookup[key]中的TInner innerItem)
{
更新程序(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);
List obj1=新列表()
{
新建testObject(){fruitId=1,name=“mango”},
新的testObject(){fructId=2,name=“grapes”},
新的testObject(){fructId=2,name=“grapes”},
新建testObject(){fruitId=4,name=“kivi”},
};
List obj2=新列表()
{
新建testObject(){fruitId=2,name=“apple”},
新建testObject(){fructId=4,name=“orange”},
};
obj1.更新(obj2,
tx=>tx.FROUTID,
ty=>ty.FROUTID,
(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);
Dictionary first=新字典()
{
{“a”,1},
{“b”,2},
{“c”,9},
{“e”,5},
};
Dictionary second=新字典()
{
{“a”,8},
{“b”,2},
{“e”,20}
};
var-kk=0;
第一,更新(第二,
f1=>f1.Key,
s1=>s1.Key,
(f1,s1)=>f1.Value=s1.Value);
它给出了以下错误

属性或索引器 'System.Collections.Generic.KeyValuePair.Value' 无法分配给--它已被读取 只有

我知道MSDN有一个限制

枚举数可用于读取 集合中的数据,但它们 无法用于修改 基础集合


是否有一种黑客/解决方法可以以通用的方式实现相同的功能?

如果您以与
字典
相同的方式查看
列表
,那么您的代码似乎是合理的

在列表示例中,您有一个
列表
,并在列表中的特定位置更新MyMutableType对象的
属性

在您的字典示例中,您有一个
字典
,您试图用另一个
MyNotMutableType
实例替换某个位置的
MyNotMutableType
实例,而不是简单地更改同一对象实例的
属性

按照列表使用的方法,您应该有一个字典,如:
Dictionary
并且在更新程序委托中,您应该只更新
MyMutableType
的属性


希望这有帮助(我的英语很差,很抱歉)

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

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


关于词典在被枚举时是只读的这一事实,我不知道答案。

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

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

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