.net - studio - microsoft.office.interop.excel c# example
Limpiar objetos de interoperabilidad de Excel con IDisposable (2)
En mi compañía, la forma más común de liberar Excel Interop Objects es usar IDisposable de la siguiente manera:
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
donde _xlApp
se creó en el constructor de la siguiente manera:
Try
_xlApp = CType(GetObject(, "Excel.Application"), Excel.Application)
Catch e As Exception
_xlApp = CType(CreateObject("Excel.Application"), Excel.Application)
End Try
Y el cliente usa la using-statement
para ejecutar el código relacionado con los objetos de interoperabilidad de Excel.
Evitamos completamente usar la regla de dos puntos . Ahora comencé a investigar cómo liberar (Excel) Interop Objects y casi todas las discusiones que encontré al respecto, como Cómo limpiar adecuadamente los objetos de interoperabilidad de Excel o Objetos de Release Excel utilizan principalmente Marshal.ReleaseComObject (), ninguno de ellos usa la Interfaz IDisposable.
Mi pregunta es: ¿Hay alguna desventaja al utilizar IDisposable Interace para liberar objetos de interoperabilidad de Excel? Si es así, ¿cuáles son estas desventajas?
Si buscas una manera más limpia, puedes usar Koogra . No es demasiado extra (solo tienes que incluir dos dll en tus refrences) y no tienes que ocuparte de la recolección de basura implícita.
El código de abajo es todo lo que se necesita para leer 10 filas de 10 columnas de un archivo de Excel sin procesos EXCEL32 o Excel.exe . Tuve este problema hace un mes y escribí instrucciones sobre cómo hacerlo. Es mucho más fácil y más limpio que tratar directamente con Excel Interop.
Koogra.IWorkbook workbook = Koogra.WorkbookFactory.GetExcel2007Reader("MyExcelFile.xlsx");
Net.SourceForge.Koogra.IWorksheet worksheet = workbook.Worksheets.GetWorksheetByName("Sheet1");
//This will invididually print out to the Console the columns A-J (10 columns) for rows 1-10.
for (uint rowIndex = 1; rowIndex <= 10; rowIndex++)
{
for (uint columnIndex = 1; columnIndex <= 10; columnIndex++)
{
Console.WriteLine(worksheet.Rows.GetRow(rowIndex).GetCell(columnIndex).GetFormattedValue());
}
}
¿Hay alguna desventaja con el IDisposable Interace
Claro, no logra absolutamente nada. El uso de Usar o Llamar a Dispose () nunca es una forma adecuada de establecer una variable en Nothing. Que es todo lo que hace tu código.
Evitamos completamente usar la regla de dos puntos.
Siéntete libre de continuar ignorándolo, es una tontería y no causa más que dolor. La afirmación implícita del autor del blog es que hacerlo obligaría al programador a usar una variable para almacenar el valor de xlApp.Workbooks. Entonces él tendría una oportunidad de luchar, más tarde, para no olvidarse de llamar a releaseObject (). Pero hay muchas más declaraciones que producen una referencia de interfaz que no usa puntos. Algo como Range (x, y), hay una referencia de objeto Range oculta que nunca verás. Tener que almacenarlos también produce código increíblemente intrincado.
Y pasar por alto solo uno es suficiente para dejar de hacer el trabajo por completo. Absolutamente imposible de depurar. Este es el tipo de código que los programadores C deben escribir. Y a menudo fallan miserablemente, los grandes programas C a menudo pierden memoria y sus programadores pasan mucho tiempo buscando esas filtraciones. No es el modo .NET por supuesto, tiene un recolector de basura para hacer esto automáticamente. Nunca se equivoca.
El problema es que es un poco lento en el cuidado del trabajo. Mucho por diseño Nadie lo nota, excepto en este tipo de código. Puede ver que el recolector de elementos no utilizados no se ejecutó, aún ve el programa de Office ejecutándose. No se cerró cuando escribió xlapp.Quit (), todavía está presente en la pestaña Procesos del Administrador de tareas. Lo que quieren que suceda es que se dé por vencido cuando lo digan.
Eso es muy posible en .NET, sin duda puede obligar al GC a hacer el trabajo:
GC.Collect()
GC.WaitForPendingFinalizers()
Boom, cada referencia de objeto Excel se libera automáticamente. No es necesario almacenar estas referencias de objeto usted mismo y llamar explícitamente a Marshal.ReleaseComObject (), el CLR lo hace por usted. Y nunca se equivoca, no usa ni necesita una "regla de dos puntos" y no tiene problemas para encontrar esas referencias ocultas de la interfaz.
Sin embargo, lo que importa mucho es exactamente dónde colocas este código. Y la mayoría de los programadores lo colocan en el lugar equivocado, en el mismo método que usó esas interfaces de Excel. Lo cual está bien, pero no funciona cuando depura el código, un capricho que se explica en esta respuesta . La forma correcta de hacerlo en el código del autor del blog es mover el código a un pequeño método auxiliar, llamémoslo DoExcelThing (). Me gusta esto:
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
Y tenga en cuenta que esto es realmente todo solo un artefacto de depuración. Los programadores simplemente odian tener que usar el Administrador de tareas para matar las instancias de zombie Excel.exe. Zombified cuando detuvo el depurador, evitando que el programa salga normalmente y recoja basura. Esto es normal También sucederá cuando su programa muera en producción por cualquier razón. Pon tu energía donde corresponde, eliminando los errores de tu código para que tu programa no muera. El GC no necesita más ayuda que eso.