例如
var query = myDic.Where(x => !blacklist.Contains(x.Key));
foreach (var item in query)
{
if (condition)
blacklist.Add(item.key+1); //key is int type
ret.add(item);
}
return ret;
这段代码有效吗?以及如何改进它?
更新
我希望我的blacklist.add(item.key+1)
会导致较小的ret
,否则会导致ToList()
。在这个意义上,{{1}}方法无法实现我的意图。
还有其他更好的想法,正确而明确。
答案 0 :(得分:2)
是。迭代集合时,严禁更改集合内部对象。
<强>更新强>
我最初将此作为评论,但这里还有一些信息:
我应该注意到,我的知识来自我很久以前读过的经验和文章。您可以执行上面的代码,因为(我相信)查询包含对黑名单中所选对象的引用。黑名单可能会改变,但不能查询。如果你严格迭代黑名单,你将无法添加到黑名单集合。
答案 1 :(得分:2)
您提供的代码不会引发异常。正在迭代的集合(myDic
)不是要修改的集合(blacklist
或ret
)。
循环的每次迭代都将针对查询谓词计算当前项,这将检查blacklist
集合以查看它是否包含当前项的键。这是懒惰的评估,因此在一次迭代中对blacklist
的更改可能会影响后续迭代,但这不会是错误。 (blacklist
在每次迭代时都被完全评估,其枚举器未被保留。)
答案 2 :(得分:2)
这样做是完全安全的,不应该有任何问题因为你没有直接修改你正在迭代的集合。虽然你正在进行影响where子句的其他更改,但它不会让你感到沮丧。
对查询(如编写)进行了延迟评估,因此在迭代集合时会更新blacklist
,并且所有后续迭代都会在迭代时看到列表中任何新添加的项目。
以上代码实际上与此相同:
foreach (var item in myDic)
{
if (!blacklist.Contains(item.Key))
{
if (condition)
blacklist.Add(item.key + 1);
}
}
所以你应该得到的是,只要你没有直接修改你正在迭代的集合(in
循环中foreach
之后的项目),你是什么做得很安全。
如果您仍然不相信,请考虑这一点以及将向控制台写出的内容:
var blacklist = new HashSet<int>(Enumerable.Range(3, 100));
var query = Enumerable.Range(2, 98).Where(i => !blacklist.Contains(i));
foreach (var item in query)
{
Console.WriteLine(item);
if ((item % 2) == 0)
{
var value = 2 * item;
blacklist.Remove(value);
}
}