Entwickler-Ecke
Basistechnologien - Problem mit LinkedList<T>.Enumerator
Bummibaer - Di 10.04.12 17:36
Titel: Problem mit LinkedList<T>.Enumerator
Hallo,
Warum geht MoveNext ausserhalb der Schleife nicht:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| List<LinkedList<int>.Enumerator> lEnumerator = new List<LinkedList<int>.Enumerator>(); for (int i = 0; i < times.Count; i++) { lEnumerator.Add(times[i].GetEnumerator()); LinkedList<int>.Enumerator le = times[i].GetEnumerator(); while (le.MoveNext()) { System.Diagnostics.Trace.WriteLine(le.Current); }
} while (lEnumerator[0].MoveNext()) { System.Diagnostics.Trace.WriteLine(lEnumerator[0].Current); } |
Danke für Hinweise,
Steffen
Th69 - Di 10.04.12 17:58
Hallo,
du mußt den Enumerator wieder mittels Reset zurücksetzen.
Warum arbeitest du von Hand mit Enumeratoren? Ist das nur ein Test?
Ralf Jansen - Di 10.04.12 18:02
times ist eine List von LinkedList's? Ohne zu verstehen wofür der Code gut sein soll fällt es mir schwer Ratschläge zu geben. Was willst du damit erreichen?
@TH69 : Das sind zwei verschiedene Enumeratoren. Muss man aber lange drauf starren um das zu sehen ;)
Bummibaer - Di 10.04.12 18:12
Tschuldigung, der Enumerator le war nur einTest. Wenn ich den rausnehme, funktioniert es auch nicht:
Hier nochmal die entscheidende Stelle:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| LinkedList<int> times = new LinkedList<int>(); List<LinkedList<int>.Enumerator> lEnumerator = new List<LinkedList<int>.Enumerator>(); for (int i = 0; i < times.Count; i++) { lEnumerator.Add(times[i].GetEnumerator()); } while (lEnumerator[0].MoveNext()) { System.Diagnostics.Trace.WriteLine(lEnumerator[0].Current); } |
Ist der Enumerator lokal?
@Th69
ich brauche das, weil ich die Werte nacheinander von einer Zeile in times[] brauche.
Vielen Dank für die schnellen Antworten,
Steffen
Ralf Jansen - Di 10.04.12 20:42
Zitat: |
ich brauche das, weil ich die Werte nacheinander von einer Zeile in times[] brauche. |
Ich sehe keinen Zusammenhang zwischen dieser Aussage und deiner Lösung :gruebel:
Der Enumerator ist ein Struct keine Klasse. Jeder Zugriff über die Indexer Property der Liste in der er steckt liefert dir eine Kopie. Du rufst MoveNext und Current also immer an Kopien des Indexers auf. Current des Indexers in der Liste ist davon aber dann natürlich nicht betroffen. Einmal den Enumerator aus der Liste holen und diese Kopie verwenden sollte helfen.
C#-Quelltext
1: 2: 3:
| LinkedList<int>.Enumerator enumerator = lEnumerator[0]; while (enumerator.MoveNext()) System.Diagnostics.Trace.WriteLine(enumerator.Current); |
Ich würde dir raten da grundsätzlich anders dranzugehen. Da ich nicht verstehe was das soll kann ich dir aber nix konkretes empfehlen. Einen statusbehafteter Struct (wie den Enumerator) solltest du aber meiden. Du wirst ständig in so Probleme laufen wie hier. Verlaß dich wenn möglich lieber auf die
foreach Magie.
Moderiert von
Th69: C#-Tags zur Hervorhebung hinzugefügt
Bummibaer - Mi 11.04.12 09:33
Hallo Ralf,
danke für Deine Bemühungen.
times ist eine List of LinkedList[s]. In ToString() möchte ich über eine Ebene der Liste iterieren.
Etwa so:
Quelltext
1: 2: 3: 4: 5:
| times[0] times[1] times[2] 0 ------ 10 ----- 20 10 ------ 15 30 ------ 40 ------ 60 |
Die LinkedList/Queue verwende ich weil ich in Echtzeit sehr viele "times"-Werte bekomme, und die nicht speichern muss.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| List<LinkedList<int>> times; Liste füllen List<LinkedList<int>.Enumerator> lEnumerator = new List<LinkedList<int>.Enumerator>(); for (int i = 0; i < times.Count; i++) { lEnumerator.Add(times[i].GetEnumerator()); } while (lEnumerator[0].MoveNext()) { System.Diagnostics.Trace.WriteLine(lEnumerator[0].Current); } |
Wenn das nicht hilft, denke ich mir was anderes aus.
Vielen Dank,
Steffen
Moderiert von
Th69: Code-Tags (zur besseren Ausrichtung als Tabelle) hinzugefügt
Kha - Mi 11.04.12 11:02
Du kannst deine Enumerator-Liste auf IEnumerator<> umstellen, um durch das Boxing die Struct-Probleme zu umgehen. Und dann könntest du den hässlichen Enumerator-Code gleich in einer allgemeinen Transpose-Methode verstecken (z.B.
diese hier [
http://stackoverflow.com/a/5039863/161659], nur dass dort das Ergebnis die Länge der kürzesten Liste hat).
Th69 - Mi 11.04.12 12:13
Ich verstehe trotzdem den Sinn der Enumeratoren hier nicht - so wie Ralf schon geschrieben hat (und es auch in der MSDN-Hilfe dazu steht:
LinkedList<T>.Enumerator [
http://msdn.microsoft.com/de-de/library/2s4xk11f.aspx]) sollte man die
foreach-Schleife dafür benutzen:
MSDN hat folgendes geschrieben: |
Hinweise
Die foreach-Anweisung in C# (for each in C++, For Each in Visual Basic) verbirgt die Komplexität der Enumeratoren. Daher empfiehlt es sich, foreach zu verwenden und den Enumerator nicht direkt zu bearbeiten.
|
Also einfach:
C#-Quelltext
1: 2: 3: 4:
| foreach (int x in times[0]) { Trace.WriteLine(x); } |
Ralf Jansen - Mi 11.04.12 12:54
Eine pragmatische Lösung um deine gezeigte tabellarische Ansicht zu generieren sähe zum Beispiel so aus. Der pragmatische Teil ist LinkedList los zu werden um einen direkten indexierten Zugriff auf die Elemente zu haben und damit die Notwendigkeit sich die Position in der LinkedList (per Enumerator) zu merken.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| for (int i = 0; i < times.Max(x => x.Count); i++) { foreach (var list in times.ConvertAll(x => x.ToArray())) { if (list.Length > i) Console.Write(list[i].ToString().PadRight(8, '-')); else Console.Write("--------"); } Console.WriteLine(); } |
Edit : times.ConvertAll sollte man lieber vor die Schleife ziehen um es nicht unnötigerweise mehrmals auszuführen.
Zitat: |
Und dann könntest du den hässlichen Enumerator-Code gleich in einer allgemeinen Transpose-Methode |
Bei einer nichtrechteckigen Matrix wie hier vermutlich nicht ganz so trivial wie im verlinkten Beitrag. Oder?
Kha - Mi 11.04.12 16:01
Ralf Jansen hat folgendes geschrieben : |
Bei einer nichtrechteckigen Matrix wie hier vermutlich nicht ganz so trivial wie im verlinkten Beitrag. Oder? |
Hm, geht so ;) . Kompiliert und nicht getestet:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
| class CompletingEnumerator<T> { public IEnumerator<T> Inner { get; set; }
public bool IsCompleted { get; set; } }
public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> source) { if (source == null) throw new ArgumentNullException("source"); var enumerators = source.Select(x => new CompletingEnumerator<T> { Inner = x.GetEnumerator() }).ToArray();
try { while (true) { foreach (var enumerator in enumerators) if (!enumerator.Inner.MoveNext()) enumerator.IsCompleted = true; if (enumerators.All(x => x.IsCompleted)) yield break;
yield return enumerators.Select(x => x.IsCompleted ? default(T) : x.Inner.Current).ToArray(); }
} finally { foreach (var enumerator in enumerators) enumerator.Inner.Dispose(); } } |
Ralf Jansen - Mi 11.04.12 17:49
Schick ;) Mal sehen ob es Bummibaer hilft. Ich denke er wird 0 und nicht vorhanden unterscheiden müssen.
Kha - Mi 11.04.12 18:11
Oh, ich hatte irgendwie Listen von Klassen in Erinnerung :O . Dann muss er vor dem Aufruf eben noch nach int? konvertieren ;) .
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!