【发布时间】:2016-04-04 20:07:26
【问题描述】:
我遇到了一个非常奇怪的问题。因此,背景是我们在 Word ContentControl 和一个自定义对象之间建立了映射,我们使用该对象来存储与该控件内的内容相关的一些信息。我们使用SortedList<ContentControl, OurCustomObject> 来维护这个映射。 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;
}
【问题讨论】:
-
能否提供 SortedList 构造函数代码?如果这就是减速发生的地方,那就是我们需要看到的...... Word 中的一个已知问题 fwiw 是使用 for + index 而不是 foreach 循环通常更快。我认为这与 Word 如何“跟踪”对象的位置有关,而不是简单地使用索引来获取它。
-
当然 - 我将代码添加到我的问题中。需要这么长时间的线路是我之前提到的那条线路,即对
Array.Sort的调用。我的理解是Array.Sort将使用比较器根据它们的范围开始对 CC 进行排序。我只是不明白为什么一旦文档中有足够数量的 CC 访问Range.Start会突然变得如此缓慢,但可以通过事先迭代它们来加快速度。让我可怜的大脑感到非常困惑!
标签: c# ms-word ms-office vsto comobject