C# 带有yield-return语句的集合更改安全性

C# 带有yield-return语句的集合更改安全性,c#,.net,yield-return,C#,.net,Yield Return,使用yield-return语句,我总是想知道如何实现版本计数: private IEnumerator<string> GetStrings() { int initialVersion = _version; // Where _version is incremented everytime the list changes foreach(string s in _listInternal) { if (initialVersion !

使用yield-return语句,我总是想知道如何实现版本计数:

private IEnumerator<string> GetStrings()
{
    int initialVersion = _version; // Where _version is incremented everytime the list changes
    foreach(string s in _listInternal)
    {
        if (initialVersion != _version)
            throw ...;
        yield return s; 
    }
}
private IEnumerator GetStrings()
{
int initialVersion=_version;//其中_version每次列表更改时都会递增
foreach(列表内部的字符串s)
{
如果(初始版本!=\u版本)
扔。。。;
收益率;
}
}
当然,在这种情况下,foreach(在_listInternal中的字符串s)会捕捉到这一点,但是如果我不使用集合或列表作为源,会有问题吗


如果我更改了创建枚举器的集合,它通常会使用这个_version字段来保护自己,以免在迭代器遍历项时被更改。当多个线程在其上工作时,这也是一个问题。

不,您永远不需要使用一个版本来获得收益回报,它们应该被视为原子版本。

没有必要,假设
\u listInternal
实际上是一个
列表。
列表
枚举器已实现此功能;如果在迭代集合时对集合进行变异,则其枚举器将引发异常,该异常将通过迭代器块向上传播

如果您的迭代器块基于一个尚未具有此行为的基础集合,或者除了您使用的某个基础集合之外还有一个可变状态,但该状态无法更改,那么您可能希望使用此模式,是的


当然,为了能够实现此模式,您需要在基础数据更改时增加版本号。有时,如果您使用的是一个无法控制其代码的集合,您就无法做到这一点。

我不理解您的问题。请您详细说明一下好吗?这是一个线程安全问题吗?@aj.toulan可能是,但通常不是。通常,它是一个单一线程,在foreach循环体中改变底层collection,类似于
foreach(列表中的var项)list.Remove(项)。我通常在这种情况下使用这个。list.RemoveAll(x=>x.ShouldDelete);其中ShouldDelete是您正在操作的列表类型中的bool属性。我相信你也可以把它写成列表@是的,这是一种在不产生错误的情况下解决特定问题的方法;我给出了一个编写不正确的代码示例,如果使用该代码,就会抛出此异常,期望调用方将其代码更改为与您的代码更接近的代码。我还演示了编写不当的代码不需要(也可能不会)多线程。当迭代器的底层数据基于枚举期间的更改时,希望迭代器引发异常是完全合适的。这是一个在很多地方都使用的相当普遍的模式,说你永远不会需要它是不正确的。没错,但我认为我所说的仍然有效。我把这个问题作为一个典型的用例。我不知道在可枚举块中抛出异常是常见的做法。我尤其不希望get方法会出现这种情况。通常,当处理需要分布、分段或枚举长度未知(如无限集)时,使用收益率返回。我也没有看到作者在foreach中操纵场景。我认为这是一个糟糕的做法,考虑到你正在改变一个foreach本身的设置。Linq有解决这些问题的方法。你是说永远不应该这样做。那完全是不真实的。在某些情况下,这样做是完全合适的,所以不,你说的不应该站得住脚。当遇到阻止序列枚举的异常问题时,应该从迭代器块抛出异常;损坏的基础数据源最符合条件。产生坏数据而不是抛出会更糟糕。至于和迭代器块在这里的使用;这只是一个例子;包括实际的工作是不必要的,只会分散注意力。“我认为这是一个糟糕的做法,考虑到你正在改变一个foreach本身的设置。”是的,它是;这就是为什么如果你发现自己处于这个位置,作为一个迭代器,你应该抛出一个异常,向开发人员表明他们做错了什么,而不是忽略问题,试图掩盖它。“Linq有解决这些问题的办法。”不,没有。它将允许您在枚举基础集合时修改它。如果你想阻止迭代器的用户这样做,你需要自己去做。我不确定你是否理解我的最后一部分,我认为这与现在无关。“产生坏数据而不是抛出数据会更糟糕。”是的,但如果您发现数据已损坏,并且获得了收益回报,我不确定您是否遵循了关注点分离。在访问数据层之前,应该有一个数据层。