简单的问题,我相信 - >我的理解是,当我在IEnumerable对象上使用foreach循环时,正在使用一个虚构的IEnumerator对象。我的问题如下:
如何在foreach循环中“捕获”处理我的对象的非法行为?我特别想看看是否修改了创建IEnumerable的原始对象。如果原件已被修改,我想抛出异常。
我目前的做法是使用版本号。如果我创建一个显式迭代器并使用MoveNext()或某些东西,这很好用,但foreach循环似乎欺骗我的基于版本的方法。
答案 0 :(得分:2)
值得注意的是,vb.net或c#中的foreach循环将对一个GetEnumerator方法进行类型化处理,该方法返回一个对象,该对象返回一个返回Boolean的MoveNext方法和一个返回合适类型的Current属性。虽然GetEnumerator()方法通常是IEnumerable< T> .GetEnumerator()的实现,但它不一定是。在某些情况下,如果GetEnumerator()返回值类型而不是类类型或盒装IEnumerable< T>,则性能可能会更好。因此,可以在实现IEnumerable< T>的对象上调用foreach循环。将使用与将对象强制转换为IEnumerable< T>的语义不同的语义。第一,
答案 1 :(得分:1)
IEnumerable接口是实际返回IEnumerator的接口,它是该接口存在的全部原因。
当调用foreach块时,调用IEnumerable.GetEnumerator()方法来获取枚举器。
如果您想跟踪每个项目,因为它们是对象类型,它们将被引用,因此您将获得更新到日期版本。在项目中,您可以实现您提到的版本控制。
public class SomeItem
{
private string _Value;
private int _Version = 0;
private int _LastKnown = 0;
public SomeItem()
{
}
public SomeItem(string value)
{
this._Value = value
}
public string Value
{
get { return this._Value; }
set { if (this._Value != value) { this._Value = value; this._Version++; } }
}
public int Version
{
get { return this._Version; }
}
public bool HasChanged
{
get { return (this._Version != _LastKnown); }
}
// Reset change tracking.
public void Reset()
{
this._LastKnown = this._Version;
}
}
在其他地方你可以在你的循环中使用这样的东西。
private List<SomeItem> _Items = new List<SomeItem>();
// Add an item.
_Items.Add(new SomeItem("ABC"));
// Add a changed item.
SomeItem itemN = new SomeItem("EFG");
itemN.Value = "XYZ";
_Items.Add(itemN);
foreach (SomeItem item in _Items)
{
if (item.HasChanged)
{
// Do stuff here.
//throw new Exception()
}
}
<强>已更新强>
或者,如果您只是想知道哪些项目已更改,您可以执行此类操作。
SomeItem[] changedItems = _Items.Where(item => item.HasChanged);
根据dlev的建议,如果你只是想知道是否有任何改变只是使用。
if (_Items.Any(item => item.HasChanged))
{
// An item has changed, do stuff.
}