【问题标题】:Make COM-visible .NET assembly release COM reference使 COM 可见的 .NET 程序集发布 COM 引用
【发布时间】:2018-08-14 22:57:40
【问题描述】:

我有一个 COM 可见的 C# 程序集。它又与第 3 方 COM 应用程序通信。我的问题是,当我从 VBA 释放对我的 C# 程序集的引用时,C# 程序集保持第 3 方应用程序处于打开状态。

' Call assembly from VBA
Dim asm : Set asm = CreateObject("MyCSharpAssembly") 

' Get a managed object exposed by the assembly
' managedObject communicates with a 3-rd party COM application
Dim managedObject : Set managedObject = asm.GetManagedObject()

' When I release managedObject from VBA, the 3rd party application stays open.
Set managedObject = Nothing

我尝试在 managedObject 中实现 IDisposable 模式并显式释放 COM 对象。这行得通,但我仍然必须从 VBA 显式调用 Dispose 方法。仅将 managedObject 的引用设置为 Nothing 是不够的。 VBA 编码人员很容易忘记这一点,他们可能认为将对象设置为 Nothing 就足够了。

有什么方法可以从 C# 的角度进行编码,还是我必须坚持使用显式的 Dispose?

【问题讨论】:

  • 您的 VBA 代码使 C# 对象有资格进行垃圾回收。如果发生这种情况,也会最终确定它用来与第 3 方组件通信的 RCW。 “如果发生这种情况”子句是问题,垃圾收集器仅在需要时运行。例如,您必须帮助另一个 C# 对象,该对象公开了一个调用 GC.Collect() 的方法。
  • this answer 中有一个绝望的方法,不知道会造成多大的麻烦。这样做的典型问题是很难找到所有的接口引用,而缺少其中一个是不可调试的失败鲸鱼。否则 GC.Collect 比 Marshal.ReleaseComObject 更好的原因。
  • 感谢您的意见,汉斯。已经阅读了这个问题,包括你建议的文章(和相关文章)一两天了,我的脑袋嗡嗡作响。他们的很多内容都超出了我的专业水平。但是,从您的第一条评论中,我了解到在 VBA 中取消引用对象时不会调用析构函数(终结器) - 这取决于 GC。这并不能解决我的问题,但让我相信我并不完全疯了。我现在会坚持使用后明确“关闭”对象的要求。

标签: c# .net vba com


【解决方案1】:

您说您实现了处置模式,但您是否实现了完整的模式,而不仅仅是公共 Dispose 方法,尤其是带有终结器的方法,例如类似于下面的东西?

~ComplexResourceHolder(){  
    Dispose(false);  
}

Dispose pattern

请注意,这仍然是不确定的;终结器的运行时间可能比 VBA 消费者将其设置为 Nothing 的时间晚得多,但至少它最终会释放对象。如果您必须有确定性版本,那么我们需要重新考虑方法。

可以简化操作的一个可能但简单的选项是仅在每个公共方法中引用第 3 方 COM 组件并在最后释放它。只要典型用法通常不会连续调用同一对象上的多个方法,这可能会起作用。

另一个简单的选项是允许 VBA 使用者将第 3 方 COM 对象分配给托管对象,以便 VBA 可以管理该组件的生命周期,而不是 .NET。

可能还有其他选择,但实施起来非常具有挑战性,而且不会万无一失。

【讨论】:

  • 我确信我正确地实现了 Dispose 模式。感谢其他建议,但在我尝试开发的场景中它们不是一个选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-11
  • 2012-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-21
相关资源
最近更新 更多