visual studio office microsoft leer how example .net excel interop com-interop

.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.