Laden...

IEnumerator<T>-Interface implementieren: Rückgabetyp von Current

Erstellt von RBA285 vor 13 Jahren Letzter Beitrag vor 13 Jahren 1.340 Views
R
RBA285 Themenstarter:in
68 Beiträge seit 2010
vor 13 Jahren
IEnumerator<T>-Interface implementieren: Rückgabetyp von Current

Hallo Forum,

folgende Klassen-Signatur ist gegeben:

class MyDictionary<TKey, TValue> : IEnumerator<TKey>

Diese Klasse soll eine eigene Dictionary-Funktionalität ähnlich des system-
eigenen Dictionarys bereitstellen. Aber darum geht es eigentlich nicht. Es
geht um die Frage, wie die Content-Property des generischen IEnumerators
implementiert wird bzw. werden soll.

Implementiere ich die Property so

public TKey Current 
                {
            get
            {
                if (_keys.Count > 0)
                    return (_keys[this._index]);
                else
                    return (default(TKey));
            }
        }

dann meckert der Compiler, dass Current keine gültige Implementierung
von IEnumerator ist, da als Rückgabewert ein Object erwartet wird.

Implementierte ich die Property so

public Object Current 
                {
            get
            {
                if (_keys.Count > 0)
                    return ((Object)_keys[this._index]);
                else
                    return ((Object)default(TKey));
            }
        }

dann meckert der Compiler, dass er eine Implementierung von Current
erwartet, die als Typ TKey zurückgibt. 8o

In der MSDN ist zudem noch dokumentiert, dass man nach Möglichkeit auf die
Implementierung des generischen IEnumerator verzichten soll und stattdessen
den nicht generischen verwenden soll. Das würde m. E. folgender
Klassensignatur entsprechen:

class MyDictionary<TKey, TValue> : IEnumerator

Dann allerdings meckert der Compiler, dass er das <T>-Argument bei
IEnumerator vermisst. Also auch keine Lösung.

Wo liegt mein (Verständnis-)Fehler?

Danke!
Robin

203 Beiträge seit 2006
vor 13 Jahren

du machst einmal deine generische implementierung


public TKey Current
{
   get { 
      if(_keys.Count <= 0) throw new ApplicationException();
     return _keys[_index];
   }
}

und dann deine explizite implementierung für IEnumerator


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

bist du aber sicher, dass du deine collection von Ienumerator und nicht von Ienumerable ableiten willst?

R
RBA285 Themenstarter:in
68 Beiträge seit 2010
vor 13 Jahren

du machst einmal deine generische implementierung

  
public TKey Current  
{  
   get {   
      if(_keys.Count <= 0) throw new ApplicationException();  
     return _keys[_index];  
   }  
}  
  

Funktioniert soweit....

und dann deine explizite implementierung für IEnumerator

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

Hier meckert der Compiler wieder, dass er das <T>-Argument vermisst.
Ich wüsste jetzt auch nicht, wie die Signatur "richtig" aussehen sollte.
Zudem bemängelt er noch immer, dass der Rückgabewert kein Object ist.
Casting bringt leider auch nix...

bist du aber sicher, dass du deine collection von Ienumerator und nicht von Ienumerable ableiten willst?

Hm, ich halte mich da an meine "Bibel" (C# 3.0 kurz & gut von O'Reilly).
In dieser steht, dass der Enumerator den Cursor für die foreach-Schleife
mit MoveNext usw. zur Verfügung stellt, inkl. Beispiel. Mir geht es hauptsächlich
um die generische Implementierung dieser Funktionalität und das dadurch
(hoffentlich) tiefere Verständnis von Generics, weniger um Alternativen.

Danke,
Robin

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo RBA285,

Hier meckert der Compiler wieder, dass er das <T>-Argument vermisst.

object System.Collections.IEnumerator.Current
{
   get { return this.Current; }
}

Generell siehe [Hinweis] Syntaxfehler selbst lösen (Compilerfehlermeldungen).

Hm, ich halte mich da an meine "Bibel" (C# 3.0 kurz & gut von O'Reilly) ...

... die du allerdings missdeutet hast. Sicher wird für foreach ein Enumerator benötigt. Aber dieser wird von foreach per IEnumerable<T>.GetEnumerator () abgerufen. Also muss deine Klasse IEnumerable<T> implementieren, um in foreach benutzt werden zu können.

herbivore

R
RBA285 Themenstarter:in
68 Beiträge seit 2010
vor 13 Jahren

Hallo herbivore,

Hier meckert der Compiler wieder, dass er das <T>-Argument vermisst.

object System.Collections.IEnumerator.Current  
{  
   get { return this.Current; }  
}  
  

Generell siehe
>
.

schon klar was der Compiler bemängelte, allerdings war mir nicht bewusst,
weshalb, deshalb hilft dieser Link - zumindest mir in diesem Fall - nicht weiter.

Hm, ich halte mich da an meine "Bibel" (C# 3.0 kurz & gut von O'Reilly) ...
... die du allerdings missdeutet hast. Sicher wird für foreach ein Enumerator
benötigt. Aber dieser wird von foreach per IEnumerable<T>.GetEnumerator ()
abgerufen. Also muss deine Klasse IEnumerable<T> implementieren, um in
foreach benutzt werden zu können.

Ok, danke, dass ging aus den Beispielfragmenten nicht hervor.

Nach längeren Versuchen und Anpassung eines (nicht ganz passenden)
Beispiels aus dem I-Net habe ich es jetzt doch noch hinbekommen:
(Anforderung war die Erstellung eines eigenen Dictionarys auf Basis zweier
eindimensionaler Listen).

namespace DictionaryEigenes
{
    //----------------------------------------
    class MyDictionary<TKey, TValue> : IEnumerable<TKey>
    //----------------------------------------
    {
        List<TKey> _keys;
        List<TValue> _values;

        //----------------------------------------
        public MyDictionary()
        //----------------------------------------
        {
            _keys = new List<TKey>();
            _values = new List<TValue>();
        }

        //----------------------------------------
        public void Add(TKey key, TValue value)
        //----------------------------------------
        {
            _keys.Add(key);
            _values.Add(value);
        }

        //----------------------------------------
        public void Remove(TKey key)
        //----------------------------------------
        {
            int index = _keys.IndexOf(key);
            if (index >= 0)
            {
                _keys.RemoveAt(index);
                _values.RemoveAt(index);
            }
        }

        //----------------------------------------
        public int IndexOf(TKey key)
        //----------------------------------------
        {
            return _keys.IndexOf(key);
        }

        //----------------------------------------
        public TValue GetValue(TKey key)
        //----------------------------------------
        {
            int index = this.IndexOf(key);
            if (index >= 0)
                return this._values[index];
            else
                return default(TValue);
        }

        //----------------------------------------
        public TKey this[int index]
        //----------------------------------------
        {
            get
            {
                return _keys[index];
            }
        }

        //----------------------------------------
        public int Count()
        //----------------------------------------
        {
            return _keys.Count;
        }

        //----------------------------------------
        public IEnumerator<TKey> GetEnumerator()
        //----------------------------------------
        {
            return new Enumerator(this);
        }

        //----------------------------------------
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        //----------------------------------------
        {
            return this.GetEnumerator();
        }


        //----------------------------------------
        public class Enumerator : IEnumerator<TKey>
        //----------------------------------------
        {
            private MyDictionary<TKey, TValue> _internalDictionary;
            private int _index;
            private TKey _current;

            //----------------------------------------
            internal Enumerator(MyDictionary<TKey, TValue> internalDictionary)
            //----------------------------------------
            {
                if (internalDictionary == null)
                    throw new ArgumentNullException("reference list cannot be null!");

                this._internalDictionary = internalDictionary;
                this._index = 0;
                this._current = default(TKey);
            }

            //----------------------------------------
            public TKey Current
            //----------------------------------------
            {
                get { return this._current; }
            }

            //----------------------------------------
            public void Dispose()
            //----------------------------------------
            {
                this.Reset();
            }

            //----------------------------------------
            object System.Collections.IEnumerator.Current
            //----------------------------------------
            {
                get { return (object)this.Current; }
            }

            //----------------------------------------
            public bool MoveNext()
            //----------------------------------------
            {
                if (this._index < this._internalDictionary.Count())
                {
                    this._current = this._internalDictionary[this._index];
                    this._index++;
                    return true;
                }
                return false;
            }

            //----------------------------------------
            public void Reset()
            //----------------------------------------
            {
                this._index = 0;
                this._current = default(TKey);
            }
        }

    }
}

Das muss ich mir morgen nochmals in Ruhe zu Gemüte führen, die
Generics haben es in sich.

Robin

203 Beiträge seit 2006
vor 13 Jahren

den (object) cast kannst du dir sparen. in c# ist ja alles ein object!

R
RBA285 Themenstarter:in
68 Beiträge seit 2010
vor 13 Jahren

den (object) cast kannst du dir sparen. in c# ist ja alles ein object!

Schon klar, war auch nur ein Versuch zur "Besänftigung" des Compilers,
da er den generischen Typ nicht als signaturkonformes Objekt akzeptieren wollte.

Robin

Hinweis von winSharp93 vor 13 Jahren

Thema abgetrennt Postfix oder Prefix Schreibweise um eine Variable zu inkrementieren?