0

簡単な質問だと思います->IEnumerableオブジェクトに対してforeachループを使用すると、架空のIEnumeratorオブジェクトが使用されていることがわかります。私の質問は次のとおりです。

オブジェクトを処理するforeachループで不正な動作を「キャッチ」するにはどうすればよいですか?特に、IEnumerableが作成された元のオブジェクトが変更されているかどうかを確認したいと思います。オリジナルが変更されている場合は、例外をスローしたいと思います。

私の現在のアプローチは、バージョン番号を使用することでした。これは、明示的なイテレータを作成してMoveNext()などを使用するとうまく機能しますが、foreachループはバージョンベースのアプローチをだましているようです。

4

2 に答える 2

2

vb.netまたはc#のforeachループは、ブール値を返すMoveNextメソッドと適切な型を返すCurrentプロパティを使用して、オブジェクトを返すGetEnumeratorメソッドをダックタイピングすることに注意してください。GetEnumerator()メソッドは通常IEnumerable <T> .GetEnumerator()の実装ですが、そうである必要はありません。場合によっては、GetEnumerator()がクラス型またはボックス化されたIEnumerable <T>ではなく値型を返すと、パフォーマンスが向上することがあります。したがって、IEnumerable <T>を実装するオブジェクトでforeachループを呼び出すと、オブジェクトが最初にIEnumerable<T>にキャストされた場合とは異なるセマンティクスが使用される可能性があります。

于 2011-09-14T04:08:08.043 に答える
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.
}
于 2011-09-14T03:18:48.247 に答える