如何比较Word Interop对象的"引用相等性"并确定一个段落所属的集合或父对象?

use*_*975 7 c# ms-word office-interop word-vba

我希望能够:

  1. 比较Word Interop COM代理在"引用相等"的基础上; 和
  2. 从特定对象(比如一个段落)映射到它来自的集合,或者至少
  3. 确定两个段落是否来自同一部分,哪个段落来自前一个段落

我为什么要这样做?我正在尝试构建一个Word加载项,其作用类似于拼写检查器,因为它在后台运行(背景我的意思是通过使用SendMessage定期从主Word线程窃取时间)并扫描文档以确定文字"令牌".我希望能够保留一组标记,并在文档更改时更新它们.一个具体的例子是,如果用户编辑给定的段落,我想重新扫描段落并更新指向该段落的数据结构.如果无法在用户编辑的段落(即选择范围的开头所在的段落)和我在数据结构中"存储"的段落之间进行映射,我就无法做到这一点.


上面第1项的示例代码

如果我写下面的VBA代码:

Dim Para1 As Paragraph
Dim Para2a As Paragraph
Dim Para2b As Paragraph
Set Para1 = ActiveDocument.Paragraphs(1)
Set Para2a = Para1.Next
Set Para2b = Para1.Next.Next.Previous
If Para2a Is Para2b Then
    Debug.Print ("Para2a Is Para2b")
Else
    Debug.Print ("Para2a Is Not Para2b")
End If
Run Code Online (Sandbox Code Playgroud)

然后我得到输出:

"Para2a Is Not Para2b"
Run Code Online (Sandbox Code Playgroud)

这可能是物理上真实的(不同的COM代理),但逻辑上不正确.我需要能够比较这些段落并确定它们在逻辑上是否是相同的基础段落.

(我打算用C#编写加载项,但上面的VBA代码演示了在编写太多代码之前需要克服的问题).

对于上面的第2和第3项,希望它们不言自明.假设我有一个段落(互操作代理)参考.我想弄清楚它在文档中的"位置".它属于第1节吗?是在页脚?如果没有这种能力,我可以合理地做一些事情,以便了解事物的来源,每次更改时都会重新扫描整个文档,这当然是非常低效的,并且对于app用户来说不够及时.

任何想法非常感谢!我很乐意根据需要发布其他信息.

小智 2

在 COM Interop 上下文中了解引用相等的细节始终是一个有趣的练习。

我不会了解Paragraph.Next()Paragraph.Previous()方法的实现细节,但是它们表现出的行为与基于 COM 的集合在运行时可调用包装器创建方面的一般行为非常相似。

通常,如果可能的话,框架会避免创建新的 RCW 实例来响应对已初始化和分配 RCW 的 COM 对象进行的其他引用。如果指向 的特定指针已存在 RCW IUnknown,则该 RCW 维护的内部引用计数将递增,然后返回 RCW。这允许框架避免增加实际 COM 对象的引用计数 ( AddRef)。

基于 COM 的集合是具有实现 的托管表示的 COM 对象IEnumerable,每次访问某个项目时似乎都会生成一个新的 RCW,即使该项目已在会话期间被访问过。

例如:

Word.Document document = Application.ActiveDocument;
Paragraphs paragraphs = document.Paragraphs;

Paragraph first = paragraphs[1];
Paragraph second = paragraphs[1];

bool thisIsFalse = (first == second);
Run Code Online (Sandbox Code Playgroud)

如果您想要进行任何类型的“引用相等”检查,您需要从基于 COM 的集合中转义,特别是在您的情况下:对象Paragraphs。您只需获取其子级并将它们存储在您自己的、纯粹管理且可预测的集合中即可做到这一点,如下所示:

List<Paragraph> niceParagraphs = paragraphs.Cast<Paragraph>().ToList();
Run Code Online (Sandbox Code Playgroud)

尽管将 LINQ 与 COM Interop 结合使用可能看起来有点可怕(如果您不这么认为……它确实应该如此!)我相当确定上面的代码是安全的,并且不会留下任何悬空引用或其他任何东西可恶的。然而,我还没有彻底测试上述代码。

不要忘记在使用完这些资源后正确释放它们,至少如果您的要求需要这种程度的谨慎的话。

  • 所以,我继续谷歌搜索,我发现,我相信,是你写的一篇文章,@Matt。把它放在这里,因为它回答了我上面的问题:http://badecho.com/2010/09/outlook-com-interop-and-reference-equality-for-unique-runtime-callable-wrapper-objects/ (4认同)