Ich habe ein sehr seltsames Problem. Der Hintergrund ist, dass wir eine Zuordnung zwischen Word ContentControl
und einem benutzerdefinierten Objekt haben, das wir verwenden, um einige Information zu speichern, die sich auf den Inhalt in dem Steuerelement bezieht. Wir verwenden eine SortedList<ContentControl, OurCustomObject>
, um diese Zuordnung aufrechtzuerhalten. Der SortedList-Teil ist nützlich, um das nächste/vorherige Inhaltssteuerelement zu finden und um schnell auf das Objekt zugreifen zu können, das einem Inhaltssteuerelement zugeordnet ist.Zugriff auf Range.Start in Loop verbessert die Leistung von Comparer
Um dies einzurichten, tun wir etwas wie folgt aus:
var dictOfObjs = Globals.ThisAddIn.Application.ActiveDocument.ContentControls
.Cast<ContentControl>()
.ToDictionary(key => key, elem => new OurCustomObject(elem));
var comparer = Comparer<ContentControl>
.Create((x, y) => x.Range.Start.CompareTo(y.Range.Start));
var list = new SortedList<ContentControl, OurCustomObject>(dictOfObjs, storedcomparer);
Das schien ziemlich gut zu funktionieren, aber ich es vor kurzem versucht, auf einem Dokument mit ~ 5000 Inhalt Kontrollen, und es verlangsamt auf ein absolutes crawl (3+ Minuten, um die SortedList zu instanziieren).
Also das ist seltsam genug, aber noch mehr Fremdheit sollte noch kommen. Ich fügte einige Protokollierung hinzu, um herauszufinden, was vor sich ging, und fand, dass das Protokollieren des Anfangs jedes ContentControl
vor der Verwendung in der Liste es um einen Faktor von ~ 60 beschleunigte. (Ja, das Hinzufügen von Logging beschleunigte es!). Hier ist der viel schnelleren Code:
var dictOfObjs = Globals.ThisAddIn.Application.ActiveDocument.ContentControls
.Cast<ContentControl>()
.ToDictionary(key => key, elem => new OurCustomObject(elem));
foreach (var pair in dictOfObjs)
{
_logger.Debug("Start: " + pair.Key.Range.Start);
}
var comparer = Comparer<ContentControl>
.Create((x, y) => x.Range.Start.CompareTo(y.Range.Start));
var list = new SortedList<ContentControl, OurCustomObject>(dictOfObjs, storedcomparer);
Der Konstruktor für SortedList ruft Array.Sort<TKey, TValue>(keys, values, comparer);
auf den Schlüssel und Werte des Wörterbuchs. Ich kann nicht herausfinden, warum der Zugriff auf die Range-Objekte in einer Schleife vorher beschleunigen würde. Vielleicht etwas mit der Reihenfolge zu tun, in der sie zugegriffen werden? Die foreach Schleife greift auf sie in der Reihenfolge zu, in der sie im Dokument erscheinen, während Array.Sort überall herum springt.
Edit: Wenn ich SortedList sage, meine ich System.Collections.Generic.SortedList<TKey, TValue>
. Hier ist der Code für den Konstruktor Ich verwende:
public SortedList(IDictionary<TKey, TValue> dictionary, IComparer<TKey> comparer)
: this((dictionary != null ? dictionary.Count : 0), comparer) {
if (dictionary==null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary);
dictionary.Keys.CopyTo(keys, 0);
dictionary.Values.CopyTo(values, 0);
Array.Sort<TKey, TValue>(keys, values, comparer);
_size = dictionary.Count;
}
Konnten Sie den SortedList-Konstruktorcode zur Verfügung stellen? Wenn das ist, wo die Verlangsamung stattfindet, müssen wir das sehen ... Ein bekanntes Problem in Word, fwiw, ist, dass es oft schneller ist, die Schleife für + index statt foreach zu verwenden.Ich denke, dass es etwas damit zu tun hat, wie Word "verfolgen" muss, wo sich die Objekte befinden, anstatt es einfach mit dem Index aufnehmen zu können. –
Sicher - ich habe den Code zu meiner Frage hinzugefügt. Die Zeile, die so lange dauert, ist diejenige, die ich bereits erwähnt habe, den Aufruf von 'Array.Sort'. Mein Verständnis ist, dass 'Array.Sort' den Vergleich verwendet, um die CCs basierend auf ihrem Bereichsstart zu sortieren. Ich verstehe einfach nicht, warum der Zugriff auf 'Range.Start' plötzlich so langsam wird, sobald eine ausreichende Anzahl von CCs im Dokument vorhanden ist, und kann dennoch beschleunigt werden, indem man sie vorher iteriert. Sehr verwirrend für mein armes Gehirn! – Zout