Możesz faktycznie zwolnić obiekt aplikacji Excel w czysty sposób, ale musisz uważać.
Porada, aby zachować nazwane odniesienie dla absolutnie każdego obiektu COM, do którego masz dostęp, a następnie jawnie go zwolnić, Marshal.FinalReleaseComObject()
jest teoretycznie poprawna, ale niestety bardzo trudna do zarządzania w praktyce. Jeśli ktoś poślizgnie się gdziekolwiek i użyje „dwóch kropek” lub iteruje komórki za pomocą for each
pętli lub innego podobnego polecenia, wówczas będziesz mieć niepowiązane obiekty COM i ryzykujesz zawieszenie. W takim przypadku nie byłoby sposobu na znalezienie przyczyny w kodzie; będziesz musiał przejrzeć cały kod naocznie i, miejmy nadzieję, znaleźć przyczynę, zadanie, które może być prawie niemożliwe w przypadku dużego projektu.
Dobrą wiadomością jest to, że tak naprawdę nie musisz utrzymywać nazwanego odwołania do zmiennej do każdego używanego obiektu COM. Zamiast tego należy wywołać, GC.Collect()
a następnie GC.WaitForPendingFinalizers()
zwolnić wszystkie (zwykle drobne) obiekty, do których nie ma się odwołania, a następnie jawnie zwolnić obiekty, do których należy nazwane odwołanie do zmiennej.
Powinieneś również zwolnić swoje nazwane odwołania w odwrotnej kolejności ważności: najpierw obiekty zakresu, potem arkusze, skoroszyty, a na końcu obiekt aplikacji Excel.
Na przykład, zakładając, że masz nazwaną zmienną obiektu Range, nazwaną zmienną xlRng
arkusza xlSheet
roboczego, nazwaną zmienną skoroszytu xlBook
i nazwaną zmienną aplikacji Excel xlApp
, wówczas kod czyszczenia może wyglądać następująco:
// Cleanup
GC.Collect();
GC.WaitForPendingFinalizers();
Marshal.FinalReleaseComObject(xlRng);
Marshal.FinalReleaseComObject(xlSheet);
xlBook.Close(Type.Missing, Type.Missing, Type.Missing);
Marshal.FinalReleaseComObject(xlBook);
xlApp.Quit();
Marshal.FinalReleaseComObject(xlApp);
W większości przykładów kodu zobaczysz do czyszczenia obiektów COM z .NET, GC.Collect()
a GC.WaitForPendingFinalizers()
wywołania i są wykonywane DWUKROTNIE jak w:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
Nie powinno to być jednak wymagane, chyba że używasz programu Visual Studio Tools for Office (VSTO), który korzysta z finalizatorów, które powodują awans całego wykresu obiektów w kolejce finalizacji. Takie obiekty nie zostaną zwolnione do następnego wyrzucania elementów bezużytecznych. Jeśli jednak nie używasz VSTO, możesz zadzwonić GC.Collect()
i GC.WaitForPendingFinalizers()
tylko raz.
Wiem, że bezpośrednie dzwonienie GC.Collect()
jest nie-nie (a na pewno robienie tego dwukrotnie brzmi bardzo bolesnie), ale szczerze mówiąc, nie można tego obejść. Poprzez normalne operacje wygenerujesz ukryte obiekty, do których nie masz żadnego odniesienia, dlatego nie możesz ich uwolnić w żaden inny sposób niż wywołanie GC.Collect()
.
To złożony temat, ale tak naprawdę to wszystko. Po ustaleniu tego szablonu dla procedury czyszczenia możesz normalnie kodować, bez potrzeby owijania itp .:-)
Mam tutaj poradnik na ten temat:
Automatyzacja programów biurowych za pomocą VB.Net / COM Interop
Jest napisany dla VB.NET, ale nie zniechęcaj się, zasady są dokładnie takie same jak przy użyciu C #.