如IEnumerable<T>.GetEnumerator
method文档中所述
集合上的某些操作可能会使枚举数无效。很明显,添加或删除元素将具有上述效果。但是什么才算修改集合呢?枚举器是否关心集合本身元素的更改?
这个问题的答案可能隐藏在this thread的答案中,但我缺少一些示例。
示例代码:
public class CollectionElement
{
public CollectionElement(int id, object someProperty)
{
ID = id;
SomeProperty = someProperty;
}
public int ID { get; }
public object SomeProperty { get; set; }
}
public class CollectionModifier
{
// This is the example collection. (List<T> implements ICollection<T>.)
private List<CollectionElement> collection = new List<CollectionElement>();
// This is another example. (Dictionary<TKey, TValue> implements ICollection<KeyValuePair<TKey, TValue>>)
private Dictionary<int, CollectionElement> dictionary = new Dictionary<int, CollectionElement>();
private void Add(int id, object someProperty)
{
CollectionElement newElement = new CollectionElement(id, someProperty);
// Both statements are obviously invalidating the enumerator of the corresponding collection.
collection.Add(newElement);
dictionary.Add(id, newElement);
}
private void Remove(int id)
{
// Both statements are obviously invalidating the enumerator of the corresponding collection.
collection.RemoveAll(item => item.ID == id);
dictionary.Remove(id);
}
private void ExchangeListElement(int index, CollectionElement newElement)
{
if (index >= collection.Count)
return;
// According to the comment by Dennis_E the following statement is invalidating the enumerator of the collection.
collection[index] = newElement;
}
private void ModifyElement(int id, object newValue)
{
CollectionElement element = collection.FirstOrDefault(item => item.ID == id);
if (element == null)
return;
#warning Is the following statement modifying the collection, hence invalidating the enumerator?
element.SomeProperty = newValue;
}
private void ExchangeElement(int id, CollectionElement newElement)
{
if (!dictionary.TryGetValue(id, out CollectionElement oldElement))
return;
#warning Is the following statement modifying the collection, hence invalidating the enumerator?
dictionary[id] = newElement;
}
}
答案 0 :(得分:1)
这完全取决于实现。甚至添加或删除元素都需要使枚举器无效,这甚至不是事实。取决于迭代器的实现(以及潜在的基础集合的详细信息),以确定对基础集合的哪些类型的更改使其不再可能继续枚举,以及哪些更改仍可以允许迭代器继续。
某些实现选择最简单的选项,并说对集合的任何更改会使枚举器无效(许多.NET集合以这种方式实现),而其他实现则可以继续迭代序列,无论基础集合的所有更改。有些介于两者之间。
如果您想知道给定序列在更改基于其的集合时将如何表现,则必须查看该集合的文档或生成该序列的任何内容。如果您要为集合创建自己的集合和/或迭代器,则由您决定哪种类型的更改使任何现有的迭代器继续处理不再明智,或者是否值得您花时间(以及相关的时间)性能成本),以支持对基础集合的部分/全部更改,同时仍对迭代的序列保持明智的行为。
答案 1 :(得分:-1)
除了Servy答案:
private int? _someValue;
public IEnumerable<int> GetValues()
{
if(_someValue != null)
{
yield return _someValue.Value;
}
}
唯一负责此代码正确性的人是代码所有者。如果在_someValue更改为null时允许枚举-多线程环境中将获得NullReferenceException。如果对象保持状态,那就更糟了:
private bool _isBlack = false;
private bool _isWhite = true;
public IEnumerable<string> GetValues()
{
if(_isBlack)
{
yield return "black";
}
if(_isWhite)
{
yield return "white";
}
}
在此示例中,如果有人开始枚举,跳到单词“ white”,则有人启用了黑色-枚举的人将不会获得此“ black”值。