C# COM对象excel互操作清理 让我说,我有一个组件是用工作簿对象做的,在那个方法体的中间部分,我已经调用了另一个类的一些方法。 例如: public class MainComponent { public void MyMainMethod() { OtherComponent otherComponent = new OtherComponent(); Workbook document; // some work with workbook object // working with document and worksheet objects. otherComponent.MethodCall(document); // some work with workbook object and it's worksheets. foreach(Worksheet sheet in document.Workheets) // do something with sheet } } public class OtherComponent { public void MethodCall(Workbook document) { string worksheetNames = ""; foreach(Worksheet sheet in document.Worksheets) worksheetNames += sheet.Name; Console.WriteLine(worksheetNames); } }
方法调用(文档);我正在使用文档,并在它的工作表中进行迭代 编辑使问题更具体。我是否应该在文档和其他Component.MethodCall(文档)的工作表上调用ReleaseCOMObject 对于如何管理这段非托管代码,我从未有过很好的解释。C# COM对象excel互操作清理 让我说,我有一个组件是用工作簿对象做的,在那个方法体的中间部分,我已经调用了另一个类的一些方法。 例如: public class MainComponent { public void MyMainMethod() { OtherComponent otherComponent = new OtherComponent(); Workbook document; // some work with workbook object // working with document and worksheet objects. otherComponent.MethodCall(document); // some work with workbook object and it's worksheets. foreach(Worksheet sheet in document.Workheets) // do something with sheet } } public class OtherComponent { public void MethodCall(Workbook document) { string worksheetNames = ""; foreach(Worksheet sheet in document.Worksheets) worksheetNames += sheet.Name; Console.WriteLine(worksheetNames); } },c#,com,excel-interop,C#,Com,Excel Interop,方法调用(文档);我正在使用文档,并在它的工作表中进行迭代 编辑使问题更具体。我是否应该在文档和其他Component.MethodCall(文档)的工作表上调用ReleaseCOMObject 对于如何管理这段非托管代码,我从未有过很好的解释。 如果有人能给我解释一下,我将不胜感激。您必须在创建本地对象的范围内手动释放所有本地对象。当通过自动化使用Office应用程序时,不要依赖垃圾收集器来清理这些对象——即使垃圾收集器做得对,也可能需要时间来启动,最终可能会出现临时对象,其中包含对您认为已经
如果有人能给我解释一下,我将不胜感激。您必须在创建本地对象的范围内手动释放所有本地对象。当通过自动化使用Office应用程序时,不要依赖垃圾收集器来清理这些对象——即使垃圾收集器做得对,也可能需要时间来启动,最终可能会出现临时对象,其中包含对您认为已经消失的其他对象的引用 如果您试图在Excel被隐藏的情况下从应用程序运行Excel,则可能会用到更多详细信息 与您绝对相关的部分是:
- 将使用Excel的每个函数包装在
块中,以捕获任何可能的异常try..catch
- 始终通过调用
明确释放所有Excel对象,然后在不需要变量时将其设置为Marshal.ReleaseComObject()
。始终在null
块中释放这些对象,以确保失败的Excel方法调用不会导致挂起的COM对象finally
- 发生错误时,请关闭正在使用的Excel实例。您不太可能从Excel相关错误中恢复,而且实例保留的时间越长,它使用资源的时间就越长
- 当您退出Excel时,请确保保护代码不受递归调用的影响-如果您的异常处理程序在您的代码正在关闭Excel的过程中试图关闭Excel,则最终会导致Excel实例死机
- 调用
方法后立即调用Application.Quit()
和GC.Collect()
,以确保.NET Framework立即释放所有Excel COM对象GC.WaitForPendingFinalizers()
otherComponent
中,您不需要释放工作簿
和文档
对象。这两个对象是在第一个对象中创建的,这意味着第一个对象是所有者。由于它是拥有顶级Excel对象的第一个对象(假设您在某处也有一个应用程序
对象),因此您的第一个对象可以调用其他组件
,传入工作簿
和文档
,然后在返回时清理它们。如果您从未在main组件
中使用过这些对象中的任何一个,那么您应该在otherComponent
中创建与Excel相关的对象,并将它们清理干净
使用COM互操作,您应该尽可能靠近需要COM对象的位置创建COM对象,并尽快明确地释放它们。这对于办公应用程序尤其如此
我创建这个类是为了使使用COM对象更容易:这个包装器是一次性的,因此您可以对COM对象使用using(…)
——当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;
}
}
}
}
使用系统;
使用System.Runtime.InteropServices;
命名空间COMHelper
{
///
///COM接口指针的一次性包装器。
///
///要包装的COM接口类型。
公共类ComPtr:IDisposable
{
私有对象m_对象;
private bool m_bDisposeDone=false;
///
///建造师
///
///
公共公司(对象)
{
if(oObject==null)
抛出(新ArgumentNullException(“ComPtr的引用无效(不能为null)”);
如果(!(Marshal.IsComObject(oObject)))
抛出(新ArgumentException(“ComPtr的类型无效(必须是COM接口指针)”);
m_oObject=oObject;
}
///
///建造师
///
///
公共ComPtr(object oObject):这个((T)oObject)
{
}
///
///析构函数
///
~ComPtr()
{
处置(虚假);
}
///
///返回包装的对象。
///
公共T对象
{
得到
{
返回((T)m_对象);
}
}
///
///隐式转换为类型T。
///
///反对投票。
///将ComPtr对象强制转换为类型T。
公共静态隐式运算符T(ComPtr对象)
{
返回(ooobject.Object);
}
///
///释放资源。
///
公共空间处置()
{
处置(真实);
GC.1(本);
}
///
///释放对象使用的重影。
///
///如果为false,则从析构函数调用该函数。
受保护的无效处置(bool bDispose)
{
尝试
{
如果(!m_bDisposeDone&&(m_oObject!=null))
{
Marshal.ReleaseComObject(m_oObject);
m_oObject=null;
}
}
最后
{
m_bDisposeDone=真;
}
}
}
}
您必须在创建本地对象的范围内手动释放所有本地对象。通过自动化使用Office应用程序时,不要依赖垃圾收集