2016-04-04 3 views
0

非常に奇妙な問題が発生している。したがって、背景は、Word ContentControlと、そのコントロール内のコンテンツに関連する情報を格納するために使用するカスタムオブジェクトとの間のマッピングがあることです。このマッピングを維持するには、SortedList<ContentControl, OurCustomObject>を使用します。 SortedListパーツは、コンテンツコントロールに関連付けられたオブジェクトにすばやくアクセスできるだけでなく、次/以前のコンテンツコントロールを見つけることができる場合に便利です。 Rangeにアクセスする。ループ内で開始するとCompareerのパフォーマンスが向上する

は、私たちは以下のような何かこれを設定するには:

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;    
} 
+0

SortedListコンストラクタコードを提供できますか?それがスローダウンが起こっている場所であれば、それは私たちが見なければならないものです.Wordの既知の問題は、foreachの代わりに+ indexを使ってループするほうが速いことです。私は、それは単にインデックスを使ってWordを取り上げるのではなく、オブジェクトがどこにあるのかを「追跡」しなければならないことと関係があると思います。 –

+0

確かに - 私は自分の質問にコードを追加しました。このように長い時間を要する行は、前述の 'Array.Sort'の呼び出しです。私の理解では、 'Array.Sort'は範囲の開始に基づいてCCをソートするためにcomparerを使います。ドキュメントにCCが十分にあると突然「Range.Start」にアクセスするのが非常に遅くなってしまっているのですが、あらかじめそれらを反復処理することでスピードアップできる理由は分かりません。私の貧しい脳には非常に混乱しています! – Zout

答えて

0

をあなたのパフォーマンスの問題のほかには、(文書が実際に静的な文書である場合を除く)、私は時間をかけて失敗しますあなたのソリューションを考えます。 Range.Startの位置は、ドキュメントの内容を追加/削除することによって変化する傾向があります。これを証明する以下の少しのマクロを追加し、VBAからそれを実行する

Sub testccstart() 

    Dim cc As ContentControl 
    Set cc = ActiveDocument.ContentControls.Add(wdContentControlRichText) 

    MsgBox cc.Range.Start 

    ActiveDocument.Range(0).InsertBefore "Blablabla" 

    MsgBox cc.Range.Start 

End Sub 

あなたがコンテンツコントロールのRange.Startは1から10まであなたがにテキストを入力する分をシフトわかりますドキュメントの開始点。したがって、ドキュメントのすべての編集では、Range.Startベースのリストを再ロードする必要があります。

あなたの質問に対する答えは、あなたがトリガーしたログを追加することで、「レイジーローディング」と呼ばれるもの(実際にアクセスされたときにのみ読み込まれるもの)です。 Office内では、常に明確ではないさまざまな最適化があります(たとえば、Excelの範囲へのアクセスは、配列を使用する方がずっと高速です)。

これはあなたのための解決策になる可能性がある場合、私はビットと不思議をテストした:

var dictOfObjs = document.ContentControls 
         .Cast<ContentControl>() 
         .ToDictionary(key => key.Range.Start, elem => new OurCustomObject(elem)); 

var comparer = Comparer<int>.Create((x, y) => x.CompareTo(y)); 

var list = new SortedList<int, OurCustomObject>(dictOfObjs, comparer); 

代わりにキーとしてコンテンツコントロールを使用しての内容を想定して(私はあなたがOurCustomObjectにすでにコンテンツコントロールを保存すると思います?)コントロールはそれぞれユニークな開始位置を持っています。開始位置をKeyとして使用すると、これは4800から5秒に1600アイテムの処理を戻しました...

+0

私はこれについても心配していました(ドキュメントの内容が変わると順序が崩れます)。しかし、実際には問題はありません。テキストを追加または削除すると、後続のすべてのコンテンツコントロールの範囲が前後にシフトしますそれぞれ、 – Zout

+0

trueですが、誰かがテキストを移動する場合は表示されません。また、ドキュメントのヘッダーとフッター、および/または図形のコンテンツコントロールにコンテンツコントロールがないと思われます。ここでそれについて読んでください:http://stackoverflow.com/questions/4605179/how-to-get-the-list-of-all-content-controls-in-the-documentコンテンツコントロールオブジェクトを使用すると非常に注意してください。詳細にテストされないと手間がかかる –

+0

解決方法は、ソートされたリストの順序を維持するためにContentControlBeforeDelete ContentControlAfterAddイベント(コンテンツコントロールの移動時に呼び出される)を使用することでした。 私はあなたが図形にCCを追加することができなかったことを認識しませんでした - 興味深い!私はそれが問題だとは思わない - CCによって包まれているコンテンツはいくらか標準化されており、私はいつも文書の通常の部分にあると信じている。 遅延ロードについては、強制的に発生させる方法があるかどうかご存知ですか?ロギングの「回避策」はひどくハッキリです。あなたのお時間をありがとう、btw。 – Zout

関連する問題