【发布时间】:2012-04-27 14:23:15
【问题描述】:
我正在做单元测试。
我的解决方案中有 2 个项目,1 是库项目,1 是测试项目。 图书馆项目有一些 com 组件。测试项目是测试库项目中的功能。而这些库函数正在使用这些 com 对象。
第一个单元测试成功执行,但是当我尝试按顺序执行 2 个单元测试时,在第二个单元测试中,当我尝试访问这些时,我收到错误“无法使用已与其底层 RCW 分离的 COM 对象” com 对象。
【问题讨论】:
标签: c#
我正在做单元测试。
我的解决方案中有 2 个项目,1 是库项目,1 是测试项目。 图书馆项目有一些 com 组件。测试项目是测试库项目中的功能。而这些库函数正在使用这些 com 对象。
第一个单元测试成功执行,但是当我尝试按顺序执行 2 个单元测试时,在第二个单元测试中,当我尝试访问这些时,我收到错误“无法使用已与其底层 RCW 分离的 COM 对象” com 对象。
【问题讨论】:
标签: c#
这意味着有人错误地使用了Marshal.ReleaseComObject,或者更糟糕的是,使用了Marshal.FinalReleaseComObject。第一个单元测试通过这种相关的副作用影响第二个单元测试,可能是在拆卸方法中。解决此问题的第一步是准确找出 是哪个 对象/访问/位置导致该异常。
发生这种情况是因为在已释放 COM 对象(COM 引用计数设置为 0)的 RCW 上调用了一个方法,这意味着 ReleaseComObject 已被调用太多次或 FinalReleaseComObject 已被调用全部。
如果您拥有一个 RCW 对象(已将其“带入 CLR”),并且它的生命周期已到,ReleaseComObject 没问题(也将变量设置为 null 以避免再次使用它)。使用FinalReleaseComObject 通常永远都不好,因为用它来正确跟踪生命周期是不可能的。诀窍是要记住单个 RCW 对象表示 COM 对象被“带入 CLR”并具有内部(非 COM)一次或多次计数器。
在许多情况中,GC 将在其终结器运行时正确处理 RCW 清理。并且当时 RCW 不是强可达的,因此无法生成异常 。使用显式ReleaseComObject [仅] 在需要严格控制 COM 生命周期时需要/有用(考虑COM 对象的“共享”Dispose)。在处理 Microsoft Office 产品的插件开发时,这很重要:)
.NET and COM Interoperability : release COM from .NET client 和反文章ReleaseComObject considered dangerous 中有更多详细信息(在我的回答中)
编码愉快。
【讨论】:
Dispose。而ReleaseComObject 应该只在需要时使用。我只是在解释导致此异常的原因。我的链接回复详细介绍了 RCW 的工作方式以及何时应使用 ReleaseComObject 以及它有哪些副作用和问题。同样,当代码错误地使用 ReleaseComObject 或 FinalReleaseComObject 时会导致此异常:即使底层 COM 对象已释放(引用计数为 0),RCW 对象(它是一个 .NET 对象)仍围绕 ).