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互操作清理 让我说,我有一个组件是用工作簿对象做的,在那个方法体的中间部分,我已经调用了另一个类的一些方法。 例如: 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应用程序时,不要依赖垃圾收集器来清理这些对象——即使垃圾收集器做得对,也可能需要时间来启动,最终可能会出现临时对象,其中包含对您认为已经

方法调用(文档);我正在使用文档,并在它的工作表中进行迭代

编辑使问题更具体。我是否应该在文档和其他Component.MethodCall(文档)的工作表上调用ReleaseCOMObject

对于如何管理这段非托管代码,我从未有过很好的解释。
如果有人能给我解释一下,我将不胜感激。

您必须在创建本地对象的范围内手动释放所有本地对象。当通过自动化使用Office应用程序时,不要依赖垃圾收集器来清理这些对象——即使垃圾收集器做得对,也可能需要时间来启动,最终可能会出现临时对象,其中包含对您认为已经消失的其他对象的引用

如果您试图在Excel被隐藏的情况下从应用程序运行Excel,则可能会用到更多详细信息

与您绝对相关的部分是:

  • 将使用Excel的每个函数包装在
    try..catch
    块中,以捕获任何可能的异常
  • 始终通过调用
    Marshal.ReleaseComObject()
    明确释放所有Excel对象,然后在不需要变量时将其设置为
    null
    。始终在
    finally
    块中释放这些对象,以确保失败的Excel方法调用不会导致挂起的COM对象
  • 发生错误时,请关闭正在使用的Excel实例。您不太可能从Excel相关错误中恢复,而且实例保留的时间越长,它使用资源的时间就越长
  • 当您退出Excel时,请确保保护代码不受递归调用的影响-如果您的异常处理程序在您的代码正在关闭Excel的过程中试图关闭Excel,则最终会导致Excel实例死机
  • 调用
    Application.Quit()
    方法后立即调用
    GC.Collect()
    GC.WaitForPendingFinalizers()
    ,以确保.NET Framework立即释放所有Excel COM对象
编辑:这是在您向问题添加更多详细信息之后

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应用程序时,不要依赖垃圾收集