Frage

Vor einiger Zeit schrieb ich eine IList Erweiterungsmethode zur Aufzählung über einen Teil einer Liste mithilfe der Indizes. Während des Refactorings wurde mir klar, dass eine ähnliche Frage durch Anrufe durchgeführt werden konnte Skip(toSkip).Take(amount). Während ich dies benchmarkierte, bemerkte ich das Skip ist nicht optimiert für IList. Mit ein bisschen googeln landete ich in einem Jon Skeet -Beitrag, Diskutieren, warum Methoden optimieren wie Skip ist gefährlich.

Soweit ich den Artikel verstehe, ist das Problem, dass keine Ausnahme in die optimierten Methoden geworfen wird, wenn die Sammlung geändert wird, aber als Kommentar heißt es jedoch, dass die MSDN -Dokumentation in Konflikten selbst steht.

Im Ienumerator.Movenext ():

Wenn Änderungen an der Sammlung vorgenommen werden, z. B. Elemente hinzuzufügen, zu ändern oder zu löschen, wird der Enumerator nicht mehr ungültig und der nächste Aufruf an MoveNext oder Reset wirft eine InvalidoperationException aus.

Im Ienumerator.getenumerator ():

Wenn Änderungen an der Sammlung vorgenommen werden, wie z. B. Hinzufügen, Änderungen oder Löschen von Elementen, ist der Enumerator nicht einverkehrt ungültig und sein Verhalten ist nicht definiert.

Ich sehe Verdienste in beiden Kongressen und bin ein bisschen verloren, ob ich optimieren soll oder nicht. Was ist eine richtige Lösung? Ich habe über eine nachgedacht IList.AssumeImmutable() nähern sich nach wie vor von AsParallel() Wie von Kris Vandermotten in den Kommentaren erwähnt. Gibt es bereits eine Implementierung oder ist es eine schlechte Idee?

War es hilfreich?

Lösung

Ich stimme Rafe zu, dass das undefinierte Verhalten korrekter ist. Nur versionierte Sammlungen können Ausnahmen veröffentlichen und nicht alle Sammlungen sind versioniert (Arrays sind das größte Beispiel). Auch versionierte Sammlungen können sich schlecht benehmen, wenn Sie genau 2^32 Änderungen zwischen Anrufen an vornehmen MoveNext.

Angenommen, Sie kümmern sich wirklich um das Versionsverhalten, die Lösung besteht darin, eine zu bekommen Enumerator für die IList und Ruf an MoveNext Auf jeder Iteration darauf:

    public static IEnumerable<T> Skip<T>(this IList<T> source, int count)
    {
        using (var e = source.GetEnumerator())
            while (count < source.Count && e.MoveNext())
                yield return source[count++];
    }

Auf diese Weise erhalten Sie O (1) Verhalten durch Indexierung, aber Sie erhalten immer noch alle Ausnahmen, MoveNext. Beachten Sie, dass wir nur anrufen MoveNext für die Ausnahme-Nebenwirkungen; Wir ignorieren die Werte, über die es aufgezählt wird.

Andere Tipps

Das Readonlycollection Die Klasse kann bei Ihrer unveränderlichen Sammlung helfen.

Mein Rat: Ich persönlich würde nicht versuchen, den Compiler zu "ausgestattet", es sei denn, Sie haben ein Leistungsproblem. Sie wissen nie, dass die nächste Version Ihren optimierten Code doppelt so langsam wie das Original ausführen kann. Nicht präventiv optimieren. Die im Framework bereitgestellten Methoden können einen wirklich optimierten Code erzeugen, der schwer zu implementieren wären.

hier ist ein Artikel von MSDN, der Informationen darüber gibt, welche Sammlungen für verschiedene Zwecke verwendet werden sollen. Ich würde eine geeignete Sammlung für die Aufgabe verwenden, anstatt zu versuchen, Skip und Nehmen zu optimieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top