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

当执行时,这是每次迭代时会发生的事情:

  1. 在枚举器上调用MoveNext
  2. 枚举器查找下一个大于十的值
  3. 然后它取该值减十并将Current属性设置为该值
  4. Current属性绑定到变量n
  5. Console.WriteLine

你可以看到没有神秘感,也没有无限循环而没有任何东西。

现在比较我的例子,假设我们遗漏了ToArray

 var itemsToRemove = myDic.Where(f => f.Value == 42); foreach (var item in itemsToRemove) myDic.Remove(item.Key); 
  1. 在枚举器上调用MoveNext
  2. 枚举器找到值为42的下一对,并将Current属性设置为该值
  3. Current属性绑定到变量item
  4. Remove

这不起作用,因为当你打开一个枚举器时, WriteLine来自集合的东西是完全没问题的,当你打开一个枚举器时,你不允许从集合中Remove某些东西。

如果你ToArray调用ToArray ,那么你首先要枚举字典并填充数组。 当我们到达foreachforeach语句在数组上打开一个枚举 ,而不是字典。 在迭代数组时,您可以从字典中删除。

您还可以遍历集合的副本

 foreach (var item in myDic.ToList()) { if (item.value == 42) myDic.remove(item.key); } 

注意foreach语句中的myDic.ToList()