会在foreach中从Dictionary中删除一个键导致问题吗? 或者我应该更好地构建一个新的词典?
例如:
1。
foreach (var item in myDic) { if (item.value == 42) myDic.remove(item.key); }
无论内括号中的语句如何影响myDic
,迭代器都能正常工作吗?
2。
var newDic = myDic.where(x=>x.value!=42).ToDictionary(x=>x.key,x=>x.value);
第二种方法是一种好习惯吗? 函数式编程和不可变?
第一种方法将在运行时崩溃,因为枚举器确保在枚举时没有人从底层集合中删除。
第二种方法是一个很好的想法,但C#字典是可变的,如果你可以用变异完成同样的事情,那么复制它们既不惯用也不高效。
这是一种典型的方式:
var itemsToRemove = myDic.Where(f => f.Value == 42).ToArray(); foreach (var item in itemsToRemove) myDic.Remove(item.Key);
编辑:在评论中回答您的问题。 以下是您的其他问题中的示例的工作原理:
myList = myList.where(x=>x>10).select(x=>x-10);
这行代码没有运行任何东西; 它完全是懒惰的。 让我们说,为了论证,我们有一个foreach
,以使它看起来更像这个问题的例子。
foreach (int n in myList) Console.WriteLine(n);
当执行时,这是每次迭代时会发生的事情:
- 在枚举器上调用
MoveNext
- 枚举器查找下一个大于十的值
- 然后它取该值减十并将
Current
属性设置为该值 - 将
Current
属性绑定到变量n
-
Console.WriteLine
吧
你可以看到没有神秘感,也没有无限循环而没有任何东西。
现在比较我的例子,假设我们遗漏了ToArray
。
var itemsToRemove = myDic.Where(f => f.Value == 42); foreach (var item in itemsToRemove) myDic.Remove(item.Key);
- 在枚举器上调用
MoveNext
- 枚举器找到值为42的下一对,并将
Current
属性设置为该值 - 将
Current
属性绑定到变量item
-
Remove
它
这不起作用,因为当你打开一个枚举器时, WriteLine
来自集合的东西是完全没问题的,当你打开一个枚举器时,你不允许从集合中Remove
某些东西。
如果你ToArray
调用ToArray
,那么你首先要枚举字典并填充数组。 当我们到达foreach
, foreach
语句在数组上打开一个枚举器 ,而不是字典。 在迭代数组时,您可以从字典中删除。
您还可以遍历集合的副本 :
foreach (var item in myDic.ToList()) { if (item.value == 42) myDic.remove(item.key); }
注意foreach
语句中的myDic.ToList()
。