使用 COM 互操作处理对象生命周期的最有效方法是什么?
-
01-07-2019 - |
题
我有一个 Windows 工作流应用程序,它使用我为 COM 自动化编写的类。我正在使用 COM 从课堂上打开 Word 和 Excel。
我目前正在 COM 帮助程序中实现 IDisposable 并使用 Marshal.ReleaseComObject()。但是,如果我的工作流失败,则不会调用 Dispose() 方法,并且 Word 或 Excel 句柄保持打开状态,并且我的应用程序将挂起。
这个问题的解决方案非常简单,但我不仅仅是解决它,我还想学习一些东西并深入了解使用 COM 的正确方法。我正在寻找“最佳”或最有效且最安全的方法来处理拥有 COM 句柄的类的生命周期。模式、最佳实践或示例代码会很有帮助。
解决方案
我看不出你有什么失败不调用 Dispose() 方法。我使用顺序工作流进行了测试,该工作流仅包含一个仅引发异常的代码活动,并且工作流的 Dispose() 方法被调用两次(这是因为标准的 WorkflowTermulated 事件处理程序)。检查以下代码:
程序.cs
class Program
{
static void Main(string[] args)
{
using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e)
{
waitHandle.Set();
};
workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set();
};
WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(WorkflowConsoleApplication1.Workflow1));
instance.Start();
waitHandle.WaitOne();
}
Console.ReadKey();
}
}
工作流程1.cs
public sealed partial class Workflow1: SequentialWorkflowActivity
{
public Workflow1()
{
InitializeComponent();
this.codeActivity1.ExecuteCode += new System.EventHandler(this.codeActivity1_ExecuteCode);
}
[DebuggerStepThrough()]
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("Throw ApplicationException.");
throw new ApplicationException();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Here you must free your resources
// by calling your COM helper Dispose() method
Console.WriteLine("Object disposed.");
}
}
}
我错过了什么吗?关于 Activity(以及 Workflow)对象的生命周期相关方法,请查看这篇文章: 活动“生命周期”方法. 。如果您只想要一篇有关处置的通用文章,请检查 这.
其他提示
基本上,您不应该在工作结束时依赖手动代码对对象调用 Dispose()。你现在可能有这样的事情:
MyComHelper helper = new MyComHelper();
helper.DoStuffWithExcel();
helper.Dispose();
...
相反,您需要使用 try 块来捕获可能触发的任何异常并在此时调用 dispose。这是规范的方式:
MyComHelper helper = new MyComHelper();
try
{
helper.DoStuffWithExcel();
}
finally()
{
helper.Dispose();
}
这是 所以 常见的是 C# 有一个特殊的构造可以生成 完全相同的代码 [看注释] 如上图所示;这是您大多数时候应该做的事情(除非您有一些特殊的对象构造语义,可以使像上面这样的手动模式更容易使用):
using(MyComHelper helper = new MyComHelper())
{
helper.DoStuffWithExcel();
}
编辑:
笔记:生成的实际代码比上面的第二个示例稍微复杂一点,因为它还引入了一个新的本地作用域,使辅助对象在 using
堵塞。就像第二个代码块被 { } 包围一样。为了澄清解释而省略了这一点。