2011-09-14 17 views
0

簡単な質問、私は信じています - > IEnumerableオブジェクト上でforeachループを使用すると想像上のIEnumeratorオブジェクトが使用されていると私は理解しています。私の質問は次の通りです:foreachループの動作をキャッチするC#

私のオブジェクトを扱うforeachループで違法な動作を "キャッチ"するにはどうすればいいですか?私は具体的には、IEnumerableが作成された元のオブジェクトが変更されているかどうかを確認する必要があります。オリジナルが変更されている場合、私は例外をスローしたい。

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

+0

"想像上のIEnumeratorオブジェクト"これはまったく虚偽ではありません。実際には、IEnumerable.GetEnumerator()の呼び出しがあります。 – BoltClock

+0

Check http://stackoverflow.com/questions/7396112/detecting-modifications-with-an-ienumerable乾杯! –

+3

"想像"どのように? –

答えて

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() 
    } 
} 

あなただけのアイテムは、あなたがこのような何かを行うことが変わってきたかを知りたい場合は

代わりに更新しました。

dlevの提案によれば、ちょうど使用が変更されたかどうかを知りたい場合は、

if (_Items.Any(item => item.HasChanged)) 
{ 
    // An item has changed, do stuff. 
} 
+0

アイテムが変更されたかどうか*チェックしているだけの場合は、_Items.Any(x => x.HasChanged)がおそらくより明確です。 – dlev

+0

@dlev Trueを更新しました。 –

2

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

関連する問題