Domanda

Ho una classe che mappa gli oggetti di oggetti, ma a differenza di dizionario è mappato in entrambi i modi.Ora sto cercando di implementare un custom IEnumerator interfaccia che scorre attraverso i valori.

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();
    }
}
È stato utile?

Soluzione

In primo luogo, non rendere la vostra collezione di oggetti di implementare IEnumerator<>.Questo porta ad un bug.(Si consideri la situazione in cui i due thread sono scorrendo la stessa collezione).

L'implementazione di un enumeratore correttamente, risulta essere non banale, così C# 2.0 speciale aggiunto supporto per la lingua per farlo, basato sul 'resa' istruzione.

Raymond Chen recente serie di post sul blog ("L'attuazione di iteratori in C# e le sue conseguenze") è un buon posto per ottenere fino a velocità.

Altri suggerimenti

Basta implementare l'interfaccia IEnumerable, non c'è bisogno di implementare IEnumerator meno di non voler fare alcune cose in enumeratore, che per il tuo caso non sembra essere necessario.

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

e che è.

CreateEnumerable() restituisce un IEnumerable che implementa 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

Ecco un esempio dal libro "Algoritmi (4 ° Edizione) Robert Sedgewick".

È stato scritto in java e ho praticamente riscritto in 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; }
        }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top