在foreach循环中捕获行为C#

时间:2011-09-14 02:11:49

标签: c# exception foreach ienumerable ienumerator

简单的问题,我相信 - >我的理解是,当我在IEnumerable对象上使用foreach循环时,正在使用一个虚构的IEnumerator对象。我的问题如下:

如何在foreach循环中“捕获”处理我的对象的非法行为?我特别想看看是否修改了创建IEnumerable的原始对象。如果原件已被修改,我想抛出异常。

我目前的做法是使用版本号。如果我创建一个显式迭代器并使用MoveNext()或某些东西,这很好用,但foreach循环似乎欺骗我的基于版本的方法。

2 个答案:

答案 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.
}