我知道基本的区别,因为ReleaseComObject
仅将某些计数器减少1,而FinalReleaseComObject
将其减少至零。
因此,我通常听到的是调用FinalReleaseComObject
,因为这样您就可以确定COM对象确实已释放。
但是,这让我感到奇怪,这个计数器是否正确?如果始终调用FinalReleaseComObject
,就不会破坏该机制。如果在调用ReleaseComObject
之前该计数器不是一个,那么可能没有原因吗?
是什么导致它不应该高于一个?
提前致谢。
PS:我的COM经验仅包括使用Excel Interop。不确定此问题是否在该域本地(即,在Office Interop外部,不经常使用FinalReleaseComObject
)。
更新1
Dan提到的article讨论了完成后如何使用ReleaseComObject
。据article理解,这是正常的方式。我认为,如果您始终如一地执行此操作,则效果会很好。在对article的评论中,作者建议有人在循环中调用ReleaseComObject
,直到它真正发布为止(article是2006年的版本,因此类似于调用FinalReleaseComObject
)。但他还指出,这可能很危险。
这使我相信始终调用FinalReleaseComObject
确实不是一个好主意,因为您可能在其他地方引发异常。正如我现在所看到的,只有在绝对确定可以的情况下,才应调用此函数。
不过,我在这件事上经验很少。我不知道如何确定。如果在不应该增加计数器的情况下,解决该问题是否更好?如果是这样,那么我会说FinalReleaseComObject
不仅仅是一种最佳实践,更是一种hack。
最佳答案
一些序言...
运行时可调用包装(RCW)仅在包装的非托管COM接口(interface)上调用IUnknown.AddRef。但是,RCW还维护着对RCW本身的托管引用数的单独计数。通过调用Marshal.ReleaseComObject减少的是托管引用的此独立计数。当托管引用的计数达到零时,RCW会在非托管COM接口(interface)上调用IUnknown.Release。
Marshal.FinalReleaseComObject通过一次调用即可将托管引用计数降至零,从而立即调用包装的非托管IUnknown.Release方法(假定托管引用计数尚未为零)。
那么,为什么同时拥有Marshal.ReleaseComObject和Marshal.FinalReleaseComObject?调用Marshal.FinalReleaseComObject只需避免编写一个重复调用Marshal.ReleaseComObject的循环,直到您希望表明自己已使用COM对象(现在是)完成确实完成为止,直到返回0。
为什么要使用Marshal.ReleaseComObject或Marshal.FinalReleaseComObject?我知道以下两个原因:
第一个方法是确保对包装的COM对象使用的非托管资源(例如文件句柄,内存等)由于对非托管IUnknown.Release()方法的结果调用而尽快释放。
第二个是确保调用非托管IUnknown.Release()方法的线程在您的控制下,而不是在终结器线程下。
如果不调用这两种Marshal方法中的任何一种,则RCW的终结器最终将在垃圾回收之后的某个时间调用非托管的IUnknown.Release()方法。
有关确证的详细信息,请参见Visual C++ Team博客条目Mixing deterministic and non-deterministic cleanup。
关于.net - 为什么使用FinalReleaseComObject代替ReleaseComObject?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1827059/