使用 IDisposable 清理 Excel 互操作对象 [英] Clean up Excel Interop Objects with IDisposable

查看:24
本文介绍了使用 IDisposable 清理 Excel 互操作对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我公司,发布 Excel Interop Objects 的常用方法是使用 IDisposable 的方式如下:

In my company the common way to release Excel Interop Objects is to use IDisposable the following way:

Public Sub Dispose() Implements IDisposable.Dispose
    If Not bolDisposed Then
        Finalize()
        System.GC.SuppressFinalize(Me)
    End If
End Sub

Protected Overrides Sub Finalize()
    _xlApp = Nothing
    bolDisposed = True
    MyBase.Finalize()
End Sub

_xlApp 在构造函数中的创建方式如下:

where _xlApp was created in the constructor the following way:

Try
    _xlApp = CType(GetObject(, "Excel.Application"), Excel.Application)
Catch e As Exception
    _xlApp = CType(CreateObject("Excel.Application"), Excel.Application) 
End Try

客户端使用using-statement来执行与excel互操作对象相关的代码.

And the client uses the using-statement to execute code concerning excel interop objects.

我们完全避免使用 两点规则.现在我开始研究如何发布(Excel)互操作对象以及我发现的几乎所有关于它的讨论,比如 如何正确清理 excel 互操作对象ReleaseExcel 对象 主要使用 Marshal.ReleaseComObject(),它们都没有使用 IDisposable 接口.

We completely avoid to use the two dot rule. Now I started researching how to release (Excel) Interop Objects and almost all discussions I found about it like How to properly clean up excel interop objects or Release Excel Objects are using mostly Marshal.ReleaseComObject(), none of them using the IDisposable interface.

我的问题是:使用 IDisposable 接口发布 excel 互操作对象有什么缺点吗?如果是这样,这些缺点是什么.

My questions is: Are there any disadvantages using the IDisposable interace for releasing excel interop objects? If so, what are these disadvantages.

推荐答案

使用 IDisposable 接口有什么缺点吗

Are there any disadvantages using the IDisposable Interace

当然,它什么也做不了.使用 Using 或调用 Dispose() 从来都不是将变量设置为 Nothing 的合适方法.这就是您的代码所做的一切.

Sure, it accomplishes absolutely nothing. Using Using or calling Dispose() is never an appropriate way to set a variable to Nothing. Which is all that your code does.

我们完全避免使用两点规则.

We completely avoid to use the two dot rule.

随意继续忽略它,这是无稽之谈,只会带来悲伤.博客作者的隐含断言是,这样做会迫使程序员使用一个变量来存储 xlApp.Workbooks 的值.所以他以后会有机会,不要忘记调用 releaseObject().但是还有更多的语句可以生成不使用点的接口引用.像 Range(x,y) 这样的东西,那里有一个你永远看不到的隐藏 Range 对象引用.不得不存储它们只会产生令人难以置信的错综复杂的代码.

Feel free to continue to ignore it, it is nonsense and causes nothing but grief. The blog author's implied assertion is that doing so would force the programmer to use a variable to store the value of xlApp.Workbooks. So he'd have a fighting chance, later, to not forget to call releaseObject(). But there are many more statements that produce an interface reference that don't use dots. Something like Range(x,y), there's a hidden Range object reference there that you'll never see. Having to store them as well just produces incredibly convoluted code.

仅仅忽略一个就足以完全无法完成工作.完全无法调试.这是 C 程序员必须编写的那种代码.并且经常惨遭失败,大型 C 程序经常泄漏内存,他们的程序员花费大量时间来查找这些泄漏.当然不是 .NET 方式,它有一个垃圾收集器来自动执行此操作.它永远不会出错.

And overlooking just one is enough to completely fail to get the job done. Utterly impossible to debug. This is the kind of code that C programmers have to write. And often failed at miserably, large C programs often leak memory and their programmers spend a great deal of time finding those leaks. Not the .NET way of course, it has a garbage collector to do this automatically. It never gets it wrong.

问题是,处理工作有点慢.非常设计.除了在这种代码中,没有人注意到这一点.您可以看到垃圾收集器没有运行,您仍然看到 Office 程序在运行.当您编写 xlapp.Quit() 时它并没有退出,它仍然存在于任务管理器的进程"选项卡中.他们想要发生的是,当他们这么说时它就退出了.

Trouble is, it is a bit slow at taking care of the job. Very much by design. Nobody ever notices this, except in this kind of code. You can see that the garbage collector didn't run, you still see the Office program running. It didn't quit when you wrote xlapp.Quit(), it is still present in the Processes tab of Task Manager. What they want to happen is for it to quit when they say so.

这在 .NET 中很有可能,您当然可以强制 GC 完成工作:

That's very possible in .NET, you can certainly force the GC to get the job done:

GC.Collect()
GC.WaitForPendingFinalizers()

Boom,每个 Excel 对象引用都会自动释放.无需自己存储这些对象引用并显式调用 Marshal.ReleaseComObject(),CLR 会为您完成.它永远不会出错,它不使用或不需要两点规则",并且可以轻松找到那些隐藏的接口引用.

Boom, every Excel object reference gets released automatically. There is no need to store these object references yourself and explicitly call Marshal.ReleaseComObject(), the CLR does it for you. And it never gets it wrong, it doesn't use or need a "two dot rule" and it has no trouble finding those hidden interface references back.

然而,重要的是确切地放置此代码的位置.大多数程序员把它放在了错误的地方,使用的方法与使用那些 Excel 界面的方法相同.这很好,但在调试代码时不起作用,这个答案中解释了这个怪癖.在博客作者的代码中正确的做法是将代码移动到一个小助手方法中,我们称之为DoExcelThing().像这样:

What matters a great deal however is exactly where you put this code. And most programmers put it in the wrong place, in the same method that used those Excel interfaces. Which is fine, but does not work when you debug the code, a quirk that's explained in this answer. The proper way to do it in the blog author's code is to move the code into a little helper method, let's call it DoExcelThing(). Like this:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    DoExcelThing()
    GC.Collect()
    GC.WaitForPendingFinalizers()
    '' Excel.exe no longer running anymore at this point
End Sub

并且请记住,这实际上只是一个调试工件.程序员只是讨厌不得不使用任务管理器来杀死僵尸 Excel.exe 实例.当他们停止调试器时被僵尸化,阻止程序正常退出并收集垃圾.这是正常.当您的程序因任何原因在生产中死亡时,也会发生这种情况.把你的精力放在它所属的地方,从你的代码中清除错误,这样你的程序就不会死.GC 不需要更多帮助.

And do keep in mind that this is truly all just a debugging artifact. Programmers just hate to have to use Task Manager to kill the zombie Excel.exe instances. Zombified when they stopped the debugger, preventing the program from exiting normally and collect garbage. This is normal. It will also happen when your program dies in production for any kind of reason. Put your energy where it belongs, getting the bugs out of your code so your program won't die. The GC doesn't need more help than that.

这篇关于使用 IDisposable 清理 Excel 互操作对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆