2011-09-14 5 views
0

간단한 질문이지만, 저는 IEnumerable 개체를 통해 foreach 루프를 사용할 때 상상의 IEnumerator 개체가 사용되고 있다는 것을 알고 있습니다. 내 질문은 다음과 같습니다 :foreach 루프의 동작 잡기 C#

내 개체를 다루는 foreach 루프에서 불법적 인 동작을 "catch"할 수 있습니까? IEnumerable이 만들어진 원래 개체가 수정되었는지 구체적으로보고 싶습니다. 원본이 수정 된 경우 예외가 발생합니다.

현재 나의 접근 방식은 버전 번호를 사용하는 것입니다. 이것은 명시 적 반복자를 만들고 MoveNext() 또는 somesuch를 사용하면 훌륭하게 작동하지만 foreach 루프는 내 버전 기반 접근 방식을 속이는 것처럼 보입니다.

+0

"상상의 IEnumerator 개체"전혀 가상이 아닙니다. 실제로 IEnumerable.GetEnumerator()를 호출합니다. – BoltClock

+0

확인 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의 제안 사항에 따라

SomeItem[] changedItems = _Items.Where(item => item.HasChanged); 

.

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 루프는 부울 적당한 유형을 반환하는 현재 속성을 반환하는 MoveNext 메서드로 객체를 반환하는 GetEnumerator 메서드를 오리 입력 점에 유의하는 가치입니다. GetEnumerator() 메서드는 일반적으로 IEnumerable <T>의 구현이 될 수 있지만 .GetEnumerator() 일 필요는 없습니다. 경우에 따라 GetEnumerator()가 클래스 형식 또는 박스형 IEnumerable이 아닌 값 형식을 반환하면 더 좋을 수도 있습니다 <T>. 따라서 IEnumerable <T>을 구현하는 개체에서 foreach 루프를 호출하면 개체가 IEnumerable <T>에 먼저 캐스팅 된 것과 다른 의미를 사용하게 될 수 있습니다.

관련 문제