用IDisposable清理Excel Interop对象 [英] Clean up Excel Interop Objects with IDisposable

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

问题描述

在我公司中,发布Excel Interop Objects的通用方法是以下列方式使用IDisposable:

  Public Sub Dispose )实现IDisposable.Dispose 
如果没有bolDisposed然后
Finalize()
System.GC.SuppressFinalize(Me)
End If
End Sub

受保护的覆盖Sub Finalize()
_xlApp = Nothing
bolDisposed = True
MyBase.Finalize()
End Sub
pre>

其中 _xlApp 是以以下方式在构造函数中创建的:

 尝试
_xlApp = CType(GetObject(,Excel.Application),Excel.Application)
捕获e作为异常
_xlApp = CType(CreateObject(Excel.Application),Excel.Application)
结束尝试

客户端使用 using-statement 执行有关excel互操作对象的代码。



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



我的问题是:使用IDisposable Interace发布excel互操作对象有什么缺点吗?

解决方案


使用IDisposable Interace有任何缺点

p>

当然,它绝对没有完成。使用使用或调用Dispose()从来不是将变量设置为Nothing的适当方式。


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

你可以自由地继续忽视它,这是废话,只是为了伤害而不要做任何事情。博客作者的暗示是这样做会强制程序员使用一个变量来存储xlApp.Workbooks的值。所以他会有一个战斗的机会,后来不要忘了调用releaseObject()。但是还有更多的语句产生不使用点的接口引用。像Range(x,y),有一个隐藏的Range对象引用,你永远不会看到。不得不存储它们只是产生令人难以置信的复杂代码。



只要一个就可以完全无法完成工作。完全不可能调试这是C程序员必须编写的那种代码。而且经常在惨败中失败,大型C程序通常会泄漏内存,程序员花费大量时间找到这些漏洞。当然不是.NET的方式,它有一个垃圾回收器自动执行。它从来没有错误。



麻烦的是,照顾这份工作有点慢。非常设计。没有人注意到这一点,除了这种代码。你可以看到垃圾收集器没有运行,你仍然看到Office程序运行。当您写入xlapp.Quit()时,它没有退出,它仍然存在于任务管理器的进程选项卡中。他们想要发生的是在它们这样说的时候退出。



这是非常可能的.NET,你可以强制GC完成工作: / p>

  GC.Collect()
GC.WaitForPendingFinalizers()
pre>

Boom,每个 Excel对象引用将自动释放。没有必要自己存储这些对象引用,并显式地调用Marshal.ReleaseComObject(),CLR为您做。它从来没有错,它不使用或需要一个两点规则,它没有麻烦找到那些隐藏的界面引用回来。






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

  Private Sub Button1_Click(ByVal sender As System.Object,ByVal e As System.EventArgs)Handles Button1.Click 
DoExcelThing()
GC.Collect()
GC.WaitForPendingFinalizers()
''此时Excel.exe不再运行
End Sub

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


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

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

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

We completely avoid to use the two dot rule. Now I started researching how to realease (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.

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

解决方案

Are there any disadvantages using the IDisposable Interace

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.

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.

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.

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.

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

GC.Collect()
GC.WaitForPendingFinalizers()

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.


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

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 Interop对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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