Очистка объектов взаимодействия Excel с помощью IDisposable
В моей компании распространенным способом выпуска объектов взаимодействия Excel является использование IDisposable следующим образом:
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
был создан в конструкторе следующим образом:
Try
_xlApp = CType(GetObject(, "Excel.Application"), Excel.Application)
Catch e As Exception
_xlApp = CType(CreateObject("Excel.Application"), Excel.Application)
End Try
И клиент использует using-statement
выполнить код относительно объектов взаимодействия Excel.
Мы полностью избегаем использовать правило двух точек. Теперь я начал исследовать, как выпускать (Excel) Interop Objects, и почти все обсуждения, которые я нашел по этому поводу, например, Как правильно очистить объекты взаимодействия Excel или Release Excel Objects, в основном использует Marshal.ReleaseComObject(), ни один из них не использует интерфейс IDisposable.
Мои вопросы: есть ли недостатки в использовании IDisposable Interace для освобождения объектов взаимодействия Excel? Если так, то каковы эти недостатки.
2 ответа
Есть ли недостатки при использовании IDisposable Interace
Конечно, это абсолютно ничего не дает. Использование Использование или вызов Dispose() никогда не является подходящим способом установить для переменной значение Nothing. Это все, что делает ваш код.
Мы полностью избегаем использовать правило двух точек.
Не стесняйтесь продолжать игнорировать это, это чепуха и не вызывает ничего, кроме горя. Подразумеваемое утверждение автора блога состоит в том, что это заставит программиста использовать переменную для хранения значения xlApp.Workbooks. Так что позже у него будет шанс не забыть вызвать releaseObject(). Но есть еще много операторов, которые создают ссылку на интерфейс, в которой не используются точки. Что-то вроде Range(x,y), там есть скрытая ссылка на объект Range, который вы никогда не увидите. Хранение их также просто производит невероятно запутанный код.
И упускать из виду только одного достаточно, чтобы полностью не справиться с работой. Совершенно невозможно отладить. Это тот код, который должны писать программисты на Си. И часто с треском проваливаются, большие программы на C часто дают утечку памяти, и их программисты тратят много времени на поиск этих утечек. Конечно, не.NET, у него есть сборщик мусора, который делает это автоматически. Это никогда не ошибается.
Проблема в том, что работа над работой немного медленная. Очень по дизайну. Никто никогда не замечает этого, кроме как в коде такого рода. Вы можете видеть, что сборщик мусора не работал, вы все еще видите, как работает программа Office. Он не вышел, когда вы написали xlapp.Quit(), он все еще присутствует на вкладке "Процессы" диспетчера задач. То, что они хотят, это чтобы они бросили, когда они так говорят.
Это очень возможно в.NET, вы, безусловно, можете заставить GC выполнить работу:
GC.Collect()
GC.WaitForPendingFinalizers()
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 no longer running anymore at this point
End Sub
И имейте в виду, что это действительно просто артефакт отладки. Программисты просто не хотят использовать диспетчер задач, чтобы убить экземпляры зомби Excel.exe. Зомбифицированы, когда они остановили отладчик, не давая программе нормально выйти и собрать мусор. Это нормально Это также произойдет, когда ваша программа умрет в производстве по любой причине. Поместите свою энергию туда, где она есть, избавившись от ошибок в вашем коде, чтобы ваша программа не умерла. GC не нуждается в большей помощи, чем это.
Если вы ищете более чистый путь, вы можете использовать Koogra. Это не очень много лишних затрат (всего две DLL, которые вы должны включить в свои ссылки), и вам не нужно иметь дело с неявной сборкой мусора.
Приведенный ниже код - это все, что нужно для чтения 10 строк по 10 столбцов из файла Excel без каких- либо процессов EXCEL32 или Excel.exe. Я имел эту проблему месяц назад и написал инструкции о том, как это сделать. Намного проще и чище, чем иметь дело с 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());
}
}