Pan*_*zza 4 .net vb.net com excel
我有以下代码(从在线教程获得).代码正在运行,但我怀疑处理Excel com对象的方式有点不合适.我们真的需要调用GC.Collect吗?或者,处理此Excel com对象的最佳方法是什么?
Public Sub t1()
Dim oExcel As New Excel.Application
Dim oBook As Excel.Workbook = oExcel.Workbooks.Open(TextBox2.Text)
'select WorkSheet based on name
Dim oWS As Excel.Worksheet = CType(oBook.Sheets("Sheet1"), Excel.Worksheet)
Try
oExcel.Visible = False
'now showing the cell value
MessageBox.Show(oWS.Range(TextBox6.Text).Text)
oBook.Close()
oExcel.Quit()
releaseObject(oExcel)
releaseObject(oBook)
releaseObject(oWS)
Catch ex As Exception
MsgBox("Error: " & ex.ToString, MsgBoxStyle.Critical, "Error!")
End Try
End Sub
Private Sub releaseObject(ByVal obj As Object)
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
Run Code Online (Sandbox Code Playgroud)
首先 - 您永远不必打电话Marshal.ReleaseComObject(...)或Marshal.FinalReleaseComObject(...)在进行Excel互操作时.这是一个令人困惑的反模式,但是有关此的任何信息,包括来自Microsoft,表明您必须从.NET手动释放COM引用的任何信息都是不正确的.事实是.NET运行时和垃圾收集器正确地跟踪和清理COM引用.对于您的代码,这意味着您可以删除整个releaseObject(...)Sub并调用它.
其次,如果要确保在进程结束时清除对进程外COM对象的COM引用(以便Excel进程关闭),则需要确保垃圾收集器运行.通过调用GC.Collect()和正确执行此操作GC.WaitForPendingFinalizers().调用两次是安全的,结束确保周期也被清理干净.
第三,当在调试器下运行时,本地引用将被人为地保持活动直到方法结束(以便局部变量检查工作).因此,GC.Collect()调用对于清理对象无效,就像rng.Cells使用相同的方法一样.您应该将执行COM interop的代码从GC清理拆分为单独的方法.
一般模式是:
Sub WrapperThatCleansUp()
' NOTE: Don't call Excel objects in here...
' Debugger would keep alive until end, preventing GC cleanup
' Call a separate function that talks to Excel
DoTheWork()
' Now Let the GC clean up (twice, to clean up cycles too)
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
End Sub
Sub DoTheWork()
Dim app As New Microsoft.Office.Interop.Excel.Application
Dim book As Microsoft.Office.Interop.Excel.Workbook = app.Workbooks.Add()
Dim worksheet As Microsoft.Office.Interop.Excel.Worksheet = book.Worksheets("Sheet1")
app.Visible = True
For i As Integer = 1 To 10
worksheet.Cells.Range("A" & i).Value = "Hello"
Next
book.Save()
book.Close()
app.Quit()
' NOTE: No calls the Marshal.ReleaseComObject() are ever needed
End Sub
Run Code Online (Sandbox Code Playgroud)
关于这个问题存在很多虚假信息和混淆,包括MSDN和StackOverflow上的许多帖子.
什么最终说服我仔细看看并找出正确的建议是这篇文章https://blogs.msdn.microsoft.com/visualstudio/2010/03/01/marshal-releasecomobject-considered-dangerous/与找到在一些StackOverflow答案的调试器下,引用保持活动的问题.
@PanPizza C#和VB.NET非常相似,;从行尾删除,Worksheets sheets = ...成为Dim sheets Worksheets = ....如果你有兴趣在编程方面做得更好,你应该真正学会如何在两者之间进行转换,因为许多.NET示例只在一个或另一个中提供,而你实际上是在限制自己.
正如本回答中提到的:如何正确清理Excel互操作对象?"永远不要使用两个点"这意味着总是逐步进入一个子对象,永远不要这样做,Dim oWS AS Excel.Worksheet = oExcel.Worksheets.Open(...)总是下到工作簿,然后下到工作表,永远不要直接从Excel.Application.
作为一般规则,您需要做的是以与创建项目相反的顺序发布项目.否则你会从其他引用下面取出它们并且它们将无法正确释放.
注意如何创建Excel Application(oExcel),然后是Excel Workbook(oBook),最后是Excel Worksheet(oWS),您需要以相反的顺序释放它们.
因此,您的代码变为:
oBook.Close()
oExcel.Quit()
releaseObject(oWS)
releaseObject(oBook)
releaseObject(oExcel)
Catch ex As Exception
Run Code Online (Sandbox Code Playgroud)
并完全从中删除此代码 Sub releaseObject(ByVal obj As Object)
Finally
GC.Collect()
Run Code Online (Sandbox Code Playgroud)
它不是必需的,GC自然发生,并且不希望你的应用程序立即释放内存,.NET池未分配内存,以便它可以很容易地在这个内存中实例化对象,而不是要求操作系统获得更多内存.
| 归档时间: |
|
| 查看次数: |
27575 次 |
| 最近记录: |