C# 使COM可见.NET程序集发布COM引用

C# 使COM可见.NET程序集发布COM引用,c#,.net,vba,com,C#,.net,Vba,Com,我有一个COM可见的C#程序集。它又与第三方COM应用程序通信。我的问题是,当我从VBA中释放对我的C#assembly的引用时,C#assembly会使第三方应用程序保持打开状态 ' Call assembly from VBA Dim asm : Set asm = CreateObject("MyCSharpAssembly") ' Get a managed object exposed by the assembly ' managedObject communicates wit

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

' 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编码人员很容易忘记这一点,他们可能认为将对象设置为“无”就足够了


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

你说你实现了Dispose模式,但你实现了完整模式,而不仅仅是public
Dispose
方法,特别是带有终结器的方法,例如类似于下面的方法

~ComplexResourceHolder(){  
    Dispose(false);  
}

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

简化操作的一个可能但过于简单的选项是只引用每个公共方法中的第三方COM组件,并在最后发布它。只要典型用法通常不连续调用同一对象上的多个方法,这可能就行了

另一个简单的选项是允许VBA使用者将第三方COM对象分配给托管对象,这样VBA就可以管理该组件的生存期,而不是.NET


可能还有其他选择,但它们的实现将非常具有挑战性,而且不会那么简单。

您的VBA代码使C#对象符合垃圾收集的条件。如果发生这种情况,它还将最终确定用于与第三方组件对话的RCW。“如果发生这种情况”子句是关键,垃圾收集器仅在需要时运行。比如说,你必须帮助另一个C#对象,它公开了一个调用GC.Collect()的方法。这样做的典型问题是很难找到所有的接口引用,并且只缺少其中一个接口引用是一个不可调试的失败案例。否则,GC.Collect比Marshal.ReleaseComObject更好。感谢您的输入。我已经读了一两天关于这个问题的文章,包括你建议的(和相关的)文章,我的脑袋嗡嗡作响。他们的很多内容都高于我的专业水平。然而,从您的第一条评论中,我发现在VBA中取消引用对象时不会调用析构函数(终结器),这取决于GC。这并不能解决我的问题,但给了我信心,我不是完全疯了。现在我将坚持使用后显式“关闭”对象的要求。我相信我正确地实现了Dispose模式。感谢其他建议,但在我尝试开发的场景中,它们不是一个选项。