Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

IEnumerator<T>-Interface implementieren: Rückgabetyp von Current
RBA285
myCSharp.de - Member



Dabei seit:
Beiträge: 68

Themenstarter:

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

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
esskar
myCSharp.de - Member

Avatar #avatar-2885.jpg


Dabei seit:
Beiträge: 203
Herkunft: Dubai

beantworten | zitieren | melden

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?
private Nachricht | Beiträge des Benutzers
RBA285
myCSharp.de - Member



Dabei seit:
Beiträge: 68

Themenstarter:

beantworten | zitieren | melden

Zitat von esskar
du machst einmal deine generische implementierung


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

Funktioniert soweit....
Zitat von esskar
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...
Zitat von esskar
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
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo RBA285,
Zitat
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).
Zitat
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
private Nachricht | Beiträge des Benutzers
RBA285
myCSharp.de - Member



Dabei seit:
Beiträge: 68

Themenstarter:

beantworten | zitieren | melden

Hallo herbivore,
Zitat von herbivore
Zitat
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).

schon klar was der Compiler bemängelte, allerdings war mir nicht bewusst,
weshalb, deshalb hilft dieser Link - zumindest mir in diesem Fall - nicht weiter.
Zitat von herbivore
Zitat
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
private Nachricht | Beiträge des Benutzers
esskar
myCSharp.de - Member

Avatar #avatar-2885.jpg


Dabei seit:
Beiträge: 203
Herkunft: Dubai

beantworten | zitieren | melden

den (object) cast kannst du dir sparen. in c# ist ja alles ein object!
private Nachricht | Beiträge des Benutzers
RBA285
myCSharp.de - Member



Dabei seit:
Beiträge: 68

Themenstarter:

beantworten | zitieren | melden

Zitat von esskar
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
private Nachricht | Beiträge des Benutzers

Moderationshinweis von winSharp93 (22.08.2010 - 09:36)

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