Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么我会得到;收集被修改;枚举操作不能执行";当不修改枚举集合时?_C#_Linq_Enumeration - Fatal编程技术网

C# 为什么我会得到;收集被修改;枚举操作不能执行";当不修改枚举集合时?

C# 为什么我会得到;收集被修改;枚举操作不能执行";当不修改枚举集合时?,c#,linq,enumeration,C#,Linq,Enumeration,我有两个字符串集合:CollectionA是存储在系统中的对象的StringCollection属性,而CollectionB是在运行时生成的列表。如果存在任何差异,则需要更新CollectionA以匹配CollectionB。所以我设计了一个简单的LINQ方法来执行删除 var strDifferences = CollectionA.Where(foo => !CollectionB.Contains(foo)); foreach (var strVar in strDifferenc

我有两个字符串集合:CollectionA是存储在系统中的对象的StringCollection属性,而CollectionB是在运行时生成的列表。如果存在任何差异,则需要更新CollectionA以匹配CollectionB。所以我设计了一个简单的LINQ方法来执行删除

var strDifferences = CollectionA.Where(foo => !CollectionB.Contains(foo));
foreach (var strVar in strDifferences) { CollectionA.Remove(strVar); }

但我得到一个
“集合被修改;枚举操作可能不会在strDifferences上执行”
错误。。。即使它与正在修改的集合是一个单独的可枚举项!我最初明确地设计这个方法是为了避免这个错误,因为我的第一个实现会产生这个错误(因为我在
CollectionA
中枚举,只是在
!CollectionB.Contains(str)
时删除)。有人能解释一下这个枚举失败的原因吗?

这两者并不是完全分开的<代码>其中不制作集合的单独副本。它在内部保留对原始集合的引用,并根据您的请求从中获取元素

您可以通过添加
ToList()
来解决问题,强制
Where
立即遍历集合

var strDifferences = CollectionA
    .Where(foo => !CollectionB.Contains(foo))
    .ToList();

Where
传回
IEnumerable
,然后在
foreach中使用它(strDifferences中的var strVar)

然后,您试图将其从创建
IEnumerable
的集合中删除。您尚未创建新列表,它正在引用
CollectionA
以从中提取下一项,因此您无法编辑
CollectionA

您也可以这样做:

var strDifferences = CollectionA.Where
  (foo => CollectionB.Contains(foo)).ToList();

CollectionA = strDifferences;
//or instead of reassigning CollectionA
CollectionA.Clear();
CollectionA.AddRange(strDifferences);

因为您正在删除不在CollectionB中的。只需查找以下内容,创建一个列表并将该列表分配给CollectionA变量。

尝试稍微修改第一行:

var strDifferences =
    CollectionA.Where(foo => !CollectionB.Contains(foo)).ToList();

我认为LINQ正在使用延迟执行您的查询。调用
ToList
将在枚举之前强制执行查询。

Ah。。。我很想使用您的替代方案(无论效果如何相同),但不幸的是,CollectionA是一个只读属性,所以我无法设置它。不过,您确实给出了更为深入的解释,因此+1是正确的。@ccornet如果无法设置它,您可以清除它并重新添加项目。我想了很久。我决定仍然采用移除方法。如果不需要更改,我不想修改CollectionA,建立一个需要删除的内容的列表可以使这一点变得非常快速和简单(只需查看strDifferences.Count是否>0)。若我构建了一个目标数组,我仍然需要检查CollectionA是否有需要删除的内容。这里不是更好吗?没有必要使用
List
@svick这是我想了很久的问题,但这是我另一天会问的问题。如果它还没有被问到,当然-咯咯笑-@GraceNote在这里捕捉到:是的,并且确保不要把它放在两行上,即。var strdifferencetemp=CollectionA.Where(foo=>!CollectionB.Contains(foo));var strDifferences=strdifferencestep.ToList();如果这样做,则集合可以由这两行之间的其他线程修改。@Markus如果是多线程,则即使将其放在一行中也没有任何区别。在那种情况下,你最好考虑不可变因素。