Вы должны будете освободить все локальные объекты вручную в области, в которой вы их создали.При использовании приложений Office через автоматизацию не полагайтесь на сборщик мусора для очистки этих объектов - даже если он правильно его выполняет, может потребоваться время, чтобы его сработало, и вы можете получить временные объекты, содержащие ссылки на другие объекты.что, по вашему мнению, уже ушло.
Это несколько связанный вопрос с более подробной информацией, которая может быть применима к вам, если вы попытаетесь запустить Excel из своего приложения со скрытым Excel.
Часть, которая определенно относится к вам, такова:
- Оберните каждую отдельную функцию, использующую Excel, в блок
try..catch
, чтобы захватить любое возможное исключение. - Всегда явно освобождатьвсе объекты Excel, вызвав
Marshal.ReleaseComObject()
, а затем установив переменные на null
, как только они вам не понадобятся.Всегда выпускайте эти объекты в блоке finally
, чтобы убедиться, что неудачный вызов метода Excel не приведет к зависанию COM-объекта. - При возникновении ошибки закройте используемый экземпляр Excel.Маловероятно, что вы сможете восстановить ошибки, связанные с Excel, и чем дольше вы сохраняете экземпляр, тем дольше он использует ресурсы.
- При выходе из Excel убедитесь, что вы защищаете этот код от рекурсивных вызовов - если вашобработчики исключений пытаются завершить работу Excel, когда ваш код уже находится в процессе завершения работы Excel, в результате вы получите мертвый экземпляр Excel.
- Вызов
GC.Collect()
и GC.WaitForPendingFinalizers()
сразу после вызова *Метод 1024 *, чтобы убедиться, что .NET Framework немедленно выпускает все COM-объекты Excel.
Редактировать : это после того, как вы добавили больше деталей к своему вопросу.
В otherComponent
вам не нужно освобождать объекты Workbook
и Document
.Эти два объекта созданы в вашем первом объекте, что означает, что первый объект является владельцем.Поскольку это первый объект, которому принадлежат ваши объекты Excel верхнего уровня (при условии, что у вас также есть объект Application
), ваш первый объект может вызвать otherComponent
, передать Workbook
и Document
, а затем при возврате очиститьих вверх.Если вы никогда не используете ни один из этих объектов в MainComponent
, вам следует создать связанные с Excel объекты внутри otherComponent
и очистить их там.
С COM-взаимодействием вы должны создавать свои COM-объекты какблизко к месту, где они вам нужны, и выпустите их явно, как только сможете.Это особенно верно для приложений Office.
Я сделал этот класс, чтобы упростить использование COM-объектов: эта оболочка одноразовая, поэтому вы можете использовать using(...)
с вашими COM-объектами - когда область действия using
закончена, оболочка освобождает COM-объект.
using System;
using System.Runtime.InteropServices;
namespace COMHelper
{
/// <summary>
/// Disposable wrapper for COM interface pointers.
/// </summary>
/// <typeparam name="T">COM interface type to wrap.</typeparam>
public class ComPtr<T> : IDisposable
{
private object m_oObject;
private bool m_bDisposeDone = false;
/// <summary>
/// Constructor
/// </summary>
/// <param name="oObject"></param>
public ComPtr ( T oObject )
{
if ( oObject == null )
throw ( new ArgumentNullException ( "Invalid reference for ComPtr (cannot be null)" ) );
if ( !( Marshal.IsComObject ( oObject ) ) )
throw ( new ArgumentException ( "Invalid type for ComPtr (must be a COM interface pointer)" ) );
m_oObject = oObject;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="oObject"></param>
public ComPtr ( object oObject ) : this ( (T) oObject )
{
}
/// <summary>
/// Destructor
/// </summary>
~ComPtr ()
{
Dispose ( false );
}
/// <summary>
/// Returns the wrapped object.
/// </summary>
public T Object
{
get
{
return ( (T) m_oObject );
}
}
/// <summary>
/// Implicit cast to type T.
/// </summary>
/// <param name="oObject">Object to cast.</param>
/// <returns>Returns the ComPtr object cast to type T.</returns>
public static implicit operator T ( ComPtr<T> oObject )
{
return ( oObject.Object );
}
/// <summary>
/// Frees up resources.
/// </summary>
public void Dispose ()
{
Dispose ( true );
GC.SuppressFinalize ( this );
}
/// <summary>
/// Frees up resurces used by the object.
/// </summary>
/// <param name="bDispose">When false, the function is called from the destructor.</param>
protected void Dispose ( bool bDispose )
{
try
{
if ( !m_bDisposeDone && ( m_oObject != null ) )
{
Marshal.ReleaseComObject ( m_oObject );
m_oObject = null;
}
}
finally
{
m_bDisposeDone = true;
}
}
}
}