C#VSTO Outlook加载项:不释放MailItem对象可能会有什么影响

时间:2019-11-19 05:53:32

标签: c# outlook vsto outlook-addin office-addins

在Outlook中与MailItems交互时使用Marshal.ReleaseComObject的重要性是什么?

我参考创建C#VSTO Outlook加载项的演练 https://docs.microsoft.com/en-us/visualstudio/vsto/walkthrough-creating-your-first-vsto-add-in-for-outlook?view=vs-2019

其中有修改现有选定邮件项目的主题和正文的示例。

void Inspectors_NewInspector(Microsoft.Office.Interop.Outlook.Inspector Inspector)
{
    Outlook.MailItem mailItem = Inspector.CurrentItem as Outlook.MailItem;
    if (mailItem != null)
    {
        if (mailItem.EntryID == null)
        {
            mailItem.Subject = "This text was added by using code";
            mailItem.Body = "This text was added by using code";
        }

    }
}

该示例结束时没有提到使用Marshal.ReleaseComObject释放邮件项目对象。

但是在https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.releasecomobject?view=netframework-4.8的.Net API参考中,他们提到:

  

您应该使用此方法来释放底层的COM对象,该对象及时保存对资源的引用,或者在必须按特定顺序释放对象时。

因此,如果我们未能在要引用的MailItem上使用Marshal.ReleaseComObject,那么显然会有一些后果?

是否存在不使用Marshal.ReleaseComObject会导致问题的特定用例?

谢谢

2 个答案:

答案 0 :(得分:1)

如果您不调用Marshal.ReleaseComObject,则该对象将作为垃圾回收器稍后释放的点被释放。通常,这不是问题-在处理大量项目时,您通常需要小心,不要使发行版具有偶然性。在这种特殊情况下,除非使用Marshal.ReleaseComObject,否则您会很好的,除非您要确保该项目已发布,以防它在外部更新,并且您不希望Outlook对象模型以陈旧的对象结尾。

请注意,Marshal.ReleaseComObject变量上的mailItem是不够的-您需要注意隐式变量,例如当您使用多点符号时。某些.Net运算符也以隐式变量结尾,as是其中之一(以及is):

void Inspectors_NewInspector(Microsoft.Office.Interop.Outlook.Inspector Inspector)
{
    object item = Inspector.CurrentItem;
    Outlook.MailItem mailItem = item as Outlook.MailItem;
    if (mailItem != null)
    {
        if (mailItem.EntryID == null)
        {
            mailItem.Subject = "This text was added by using code";
            mailItem.Body = "This text was added by using code";
        }
        Marshal.ReleaseComObject(mailItem);
    }
    Marshal.ReleaseComObject(item);
}

答案 1 :(得分:0)


TL; DR:不要调用Marshal.ReleaseComObject,因为它没有用处,更重要的是,它是危险。请参见下面的引文。


  

在Outlook中与MailItems交互时使用Marshal.ReleaseComObject的重要性是什么?

不需要,您不需要。

  

如果我们在引用的MailItem上不使用Marshal.ReleaseComObject,那么显然会有一些后果吗?

不正确。

  

是否存在不使用Marshal.ReleaseComObject会导致问题的特定用例?

称这是正确的情况。

MSDN article备注部分有些混乱,并且令人误解

该行:

  

您应该使用此方法来释放底层的COM对象,该对象及时保存对资源的引用,或者在必须按特定顺序释放对象时。

...应该真的之后更重要:

  

因此,ReleaseComObject 仅在绝对必要时使用。如果要调用此方法以确保在确定的时间释放COM组件,请考虑改用FinalReleaseComObject方法

...并且:

  

此方法使您可以强制释放RCW参考计数,以便它在您需要的时候准确发生。但是,对ReleaseComObject的不正确使用可能会导致您的应用程序失败,或者可能导致访问冲突

实际上,在正常使用中,您根本不需要调用此方法。

最后,由于您要为Outlook制作外接程序,因此也几乎不需要释放COM对象,因为您访问的任何对象都是由Outlook本身创建的,并且您的代码在与Outlook相同的进程空间中运行。 Outlook已经知道这些对象,并且知道何时摆脱它们。并不是说您正在启动一个外部进程,例如说MS Word,并且在通过COM进行通信后,对Word的孤立实例感到担忧。

Hans Passant说:

  

不需要自己存储这些对象引用并显式调用Marshal.ReleaseComObject(),CLR会为您完成... more

另请参见

(尽管提到了Excel,但链接仍然相关,因为Outlook和Excel都使用COM)