2009-06-29 26 views
1

我正在嘗試開發一個類型來跟蹤列表中的當前迭代位置。鍵入使用IEnumerable跟蹤列表的位置

我最好想用foreach循環使用IEnumerable接口,但接口沒有啓動/停止事件或掛鉤方法來重置計數。

目前我已經創建了返回列表中的下一個值的GetNext()方法,並遞增1

計數有誰知道我可以使用IEnumerable的,所以我可以用同類型實現相同的功能一個foreach循環?

因此,例如;想象一個列表包含10個項目。一種方法可以將類型的一個實例迭代到位置4,然後方法2將從位置5到6迭代相同的實例,然後方法3將從位置7迭代到剩餘的10 - 所以類型實例跟蹤當前位置。

任何想法都非常讚賞(代碼如下所示)。謝謝

public sealed class PositionTracker<T> : IEnumerable 
{ 
    private readonly object _syncLock = new object(); 
    private readonly IList<T> _list = new List<T>(); 
    private int _current; 

    public PositionTracker(IList<T> list) 
    { 
     _list = list; 
    } 

    public T GetCurrent() 
    { 
     lock (_syncLock) 
     { 
      return _list[_current]; 
     } 
    } 

    public T GetNext() 
    { 
     lock (_syncLock) 
     { 
      T t = GetCurrent(); 
      if (_current < _list.Count - 1) 
      { 
       _current++; 
      } 
      return t; 
     } 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     lock (_syncLock) 
     { 
      return _list.GetEnumerator(); 
     } 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    public void Reset() 
    { 
     lock (_syncLock) 
     { 
      _current = 0; 
     } 
    } 

    public int Count 
    { 
     get 
     { 
      lock (_syncLock) 
      { 
       return _list.Count; 
      } 
     } 
    } 
} 

[TestFixture] 
public class PositionTrackerTests 
{ 
    [Test] 
    public void Position_CurrentPosition_Test() 
    { 
     List<string> list = new List<string>(new string[] { "A", "B", "C", "D" }); 
     PositionTracker<string> positionTracker = new PositionTracker<string>(list); 

     Assert.IsTrue(positionTracker.GetNext().Equals("A")); 
     Assert.IsTrue(positionTracker.GetNext().Equals("B")); 
     Assert.IsTrue(positionTracker.GetNext().Equals("C")); 
     Assert.IsTrue(positionTracker.GetNext().Equals("D")); 
    } 
} 

回答

1

檢查此鏈接:foreach with generic List, detecting first iteration when using value type

有通過喬恩斯基特到SmartEnumerable類的鏈接。它基本上是IEnumerable的包裝器,它爲您提供了一個包含項目索引的公共類SmartEnumerable<string>.Entry

而且,沒有什麼可以阻止你這樣做:

public class MyClass 
{ 
    private List<String> list = new List<String>() { "1", "2", "3", "4", "5" } 

    public IEnumerable<String> GetItems(int from, int to) 
    { 
      for (int i=from; i<to; i++) 
       yield return list[i]; 
    } 
} 
0

可以實現這個最有擴展方法,以及Enumerable.SelectWhere重載。

兩個SelectWhere具有其中委託傳遞兩個項目,其索引重載:

var input = new[]{'a','b','c','d'}; 
var indexed = input.Select((v,i) => new { Value = v, Index = i }); 
foreach (var v in indexed) { 
    Console.WriteLine("Index #{0} is '{1}'", v.Index, v.Value); 
} 

之前的第一個和最後一個項目後(觸發代表,但只有當至少有一個項目):

public static IEnumerable<T> StartAndEnd<T>(this IEnumerable<T> input, 
            Action onFirst, 
            Action onLast) { 
    var e = input.GetEnumerator(); 
    if (!e.MoveNext()) { yield break; } 
    onFirst(); 
    do { 
    yield return e.Current; 
    } while (e.MoveNext()); 
    onLast(); 
} 

,然後用它作爲:

var input = new[]{'a','b','c','d'}; 
var indexed = input.StartAndEnd(() => { Console.WriteLine("First!");}, 
           () => { Console.WriteLine("Last!");}) 
        .Select((v,i) => new { Value = v, Index = i }); 
foreach (var v in indexed) { 
    Console.WriteLine("Index #{0} is '{1}'", v.Index, v.Value); 
} 

其中給出結果:

 
First! 
Index #0 is 'a' 
Index #1 is 'b' 
Index #2 is 'c' 
Index #3 is 'd' 
Last! 

代表們可以設置一個本地(通過形成封閉件),這是在一個循環中進行檢查。

一個更復雜的版本可以在序列的最後一個元素之前調用onLast委託,但是這需要在產生該元素之前緩衝序列的一個元素來檢測結束。