非常に奇妙な問題が発生しています。したがって、その背景には、WordContentControl
と、そのコントロール内のコンテンツに関連する情報を格納するために使用するカスタム オブジェクトとの間のマッピングがあります。SortedList<ContentControl, OurCustomObject>
このマッピングを維持するためにa を使用します。SortedList パーツは、コンテンツ コントロールに関連付けられたオブジェクトにすばやくアクセスできるだけでなく、次/前のコンテンツ コントロールを見つけるのにも役立ちます。
これを設定するには、次のようにします。
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);
これはかなりうまくいくように見えましたが、最近、約 5000 のコンテンツ コントロールを含むドキュメントで試してみたところ、完全にクロール (SortedList のインスタンス化に 3 分以上) まで遅くなりました。
それだけでも十分に奇妙ですが、さらに奇妙なことはまだありませんでした。何が起こっているのかを把握するためにログを追加したところContentControl
、リストでそれらを使用する前にそれぞれの開始をログに記録すると、最大 60 倍高速化されることがわかりました。(はい、ロギングを追加すると速度が上がりました!)。はるかに高速なコードは次のとおりです。
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);
SortedList のコンストラクターArray.Sort<TKey, TValue>(keys, values, comparer);
は、ディクショナリのキーと値を呼び出します。事前にループ内の Range オブジェクトにアクセスすると速度が向上する理由がわかりません。たぶん、それらがアクセスされる順序と関係がありますか?foreach ループは、ドキュメントに表示される順序でそれらにアクセスしますが、Array.Sort はあちこち飛び回ります..
編集:私がSortedListと言うとき、私はSystem.Collections.Generic.SortedList<TKey, TValue>
. 私が使用しているコンストラクターのコードは次のとおりです。
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;
}