2008-09-10 4 views
11

У меня есть класс, который отображает объекты в объекты, но в отличие от словаря он отображает их в обоих направлениях. Теперь я пытаюсь реализовать пользовательский интерфейс IEnumerator, который выполняет итерацию через значения.Как реализовать интерфейс IEnumerator?

public class Mapper<K,T> : IEnumerable<T>, IEnumerator<T> 

{ 
    C5.TreeDictionary<K,T> KToTMap = new TreeDictionary<K,T>(); 
    C5.HashDictionary<T,K> TToKMap = new HashDictionary<T,K>(); 

    public void Add(K key, T value) 
    { 
     KToTMap.Add(key, value); 
     TToKMap.Add(value, key); 

    } 

    public int Count 
    { 
     get { return KToTMap.Count; } 
    } 


    public K this[T obj] 
    { 
     get 
     { 
      return TToKMap[obj]; 
     } 
    } 

    public T this[K obj] 
    { 
     get 
     { 
      return KToTMap[obj]; 
     } 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     return KToTMap.Values.GetEnumerator(); 
    } 

    public T Current 
    { 
     get { throw new NotImplementedException(); } 
    } 

    public void Dispose() 
    { 
     throw new NotImplementedException(); 
    } 

    object System.Collections.IEnumerator.Current 
    { 
     get { throw new NotImplementedException(); } 
    } 

    public bool MoveNext() 
    { 
     ; 
    } 

    public void Reset() 
    { 
     throw new NotImplementedException(); 
    } 
} 

ответ

18

Во-первых, не делайте ваш объект коллекции реализующим IEnumerator <>. Это приводит к ошибкам. (Рассмотрим ситуацию, когда два потока повторяются по одной коллекции).

Реализация перечислителя корректно оказывается нетривиальной, поэтому C# 2.0 добавила специальную поддержку языка для этого, основываясь на операторе return return.

Недавняя серия сообщений блога Раймонда Чена («Реализация итераторов в C# и его последствиях») - хорошее место, чтобы подняться до скорости.

8

Просто реализовать IEnumerable интерфейс, нет необходимости для реализации IEnumerator, если вы не хотите, чтобы сделать некоторые специальные вещи в счетчику, что для вашего случая, кажется, не потребуется.

public class Mapper<K,T> : IEnumerable<T> { 
    public IEnumerator<T> GetEnumerator() 
    { 
     return KToTMap.Values.GetEnumerator(); 
    } 
} 

и все.

+0

Так я сделал это сначала, но позже понял, что я хотел бы использовать для каждого на этом объекте, чтобы добраться до значений. – 2008-09-10 13:28:14

6

CreateEnumerable() возвращает IEnumerable который реализует GetEnumerator()

public class EasyEnumerable : IEnumerable<int> { 

    IEnumerable<int> CreateEnumerable() { 
     yield return 123; 
     yield return 456; 
     for (int i = 0; i < 6; i++) { 
      yield return i; 
     }//for 
    }//method 

    public IEnumerator<int> GetEnumerator() { 
     return CreateEnumerable().GetEnumerator(); 
    }//method 

    IEnumerator IEnumerable.GetEnumerator() { 
     return CreateEnumerable().GetEnumerator(); 
    }//method 

}//class 
2

Вот пример из книги Роберта Седжуика «Алгоритмы (4-е издание)».

Это было написано в java, и я в основном переписал его на C#.

public class Stack<T> : IEnumerable<T> 
{ 
    private T[] array; 

    public Stack(int n) 
    { 
     array = new T[n]; 
    } 

    public Stack() 
    { 
     array = new T[16]; 
    } 

    public void Push(T item) 
    { 
     if (Count == array.Length) 
     { 
      Grow(array.Length * 2); 
     } 

     array[Count++] = item; 
    } 

    public T Pop() 
    { 
     if (Count == array.Length/4) 
     { 
      Shrink(array.Length/2); 
     } 

     return array[--Count]; 
    } 

    private void Grow(int size) 
    { 
     var temp = array; 
     array = new T[size]; 
     Array.Copy(temp, array, temp.Length); 
    } 

    private void Shrink(int size) 
    { 
     Array temp = array; 
     array = new T[size]; 
     Array.Copy(temp,0,array,0,size); 
    } 

    public int Count { get; private set; } 
    public IEnumerator<T> GetEnumerator() 
    { 
     return new ReverseArrayIterator(Count,array); 
    } 

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


    // IEnumerator implementation 
    private class ReverseArrayIterator : IEnumerator<T> 
    { 
     private int i; 

     private readonly T[] array; 

     public ReverseArrayIterator(int count,T[] array) 
     { 
      i = count; 
      this.array = array; 
     } 

     public void Dispose() 
     { 

     } 

     public bool MoveNext() 
     { 
      return i > 0; 
     } 

     public void Reset() 
     { 

     } 

     public T Current { get { return array[--i]; } } 

     object IEnumerator.Current 
     { 
      get { return Current; } 
     } 
    } 
}