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
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?
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
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
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
den (object) cast kannst du dir sparen. in c# ist ja alles ein object!
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
Thema abgetrennt Postfix oder Prefix Schreibweise um eine Variable zu inkrementieren?