ArcEngine-小改进源码的ComReleaser类

ArcEngine-小改进源码的ComReleaser类

虽然ArcEngine有自己的ComReleaser,放在ESRI.ArcGIS.ADF.Connection.Local.dll中,但是经常在项目中引用不到,或者在低版本的AO中不存在,所以自己看了源码,然后加上自己的一些理解做了改进,放到项目中直接用。

ComReleaser代码

using System;
using System.Collections;
using System.Runtime.InteropServices;
/// <summary>
/// Com对象释放器
/// </summary>
[Serializable]
public class ComReleaser : IDisposable
{
    private ArrayList m_array;
    /// <summary>
    /// Default Constructor
    /// </summary>
    public ComReleaser()
    {
        m_array = ArrayList.Synchronized(new ArrayList());
    }

    /// <summary>
    /// Destructor
    /// </summary>
    ~ComReleaser()
    {
        Dispose(disposing: false);
    }

    /// <summary>
    /// Manages the lifetime of any COM object.  The method will deterministically release the object during the dispose process.
    /// </summary>
    /// <remarks>
    /// Marshal.ReleaseComObject will be called during the disposal process on this Interface pointer until its RCW
    /// reference count becomes 0.  
    /// NOTE: Do not add ServerObject interfaces like IMapServer, IGeocodeServer, IMapServerLayout or IMapServerObjects.
    /// </remarks>
    /// <param name="o">The COM object to manage.</param>
    public void ManageLifetime(object o)
    {
        m_array.Add(o);
    }

    /// <summary>
    /// Implementation of IDisposable method Dispose()
    /// The Dispose method should release all the resources that it owns for unmanaged code resources.
    /// </summary>
    public void Dispose()
    {
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// Dispose method implementation from IDisposable Interface
    /// </summary>
    /// <param name="disposing">
    /// Boolean value indicating to the method whether
    /// or not it should also dispose managed objects
    /// </param>
    protected virtual void Dispose(bool disposing)
    {
        int count = m_array.Count;
        //从后往前释放,因为添加的顺序总是从大到小,先释放小对象
        for (int i = count - 1; i >= 0; i--)
        {
            object comObj = m_array[i];
            m_array.RemoveAt(i);
            if (comObj != null && Marshal.IsComObject(comObj))
            {
                while (Marshal.ReleaseComObject(comObj) > 0)
                {
                }
            }
        }
        if (disposing)
        {
            m_array = null;
        }
    }

    /// <summary>
    /// Decrements the reference count to zero of the supplied runtime callable wrapper.
    /// </summary>
    /// <param name="o">The COM object to release.</param>
    public static void ReleaseCOMObject(object o)
    {
        if (o != null && Marshal.IsComObject(o))
        {
            while (Marshal.ReleaseComObject(o) > 0)
            {
            }
        }
    }
}

整个ComReleaser实现了IDisposable接口,可以在Using域中把创建的COM对象通过ManageLifetime方法加到内部的ArrayList中,然后在Using作用域结束的时候,从后往前遍历释放添加的COM对象。
这个类的好处在于在面对业务中大量创建使用的COM对象,比如IWorkspace、IFeatureClass、ICursor等时,不用使用try...finally写很丑的释放代码。而且按照一般的业务代码逻辑,通常都是从大到小的创建对象IWorkspace->->IFeatureDataset->IFeatureClass->ICursor等,那么依次添加到内部ArrayList后,再反向释放,能减少几次引用计数,释放速度更快,释放对象更干净。

使用实例

using (ComReleaser comReleaser = new ComReleaser())
{
    IWorkspace workspace = AEComFunc.OpenFeatureWorkspace(dbPath);
    comReleaser.ManageLifetime(workspace);
    string xzydyh = "XZYDYH";
    IFeatureClass xzydyh_fc = (workspace as IFeatureWorkspace).OpenFeatureClass(xzydyh);
    comReleaser.ManageLifetime(xzydyh_fc);
    ICursor cursor = xzydyh_fc.Search(null, true) as ICursor;
    comReleaser.ManageLifetime(cursor);
    ESRI.ArcGIS.Geodatabase.IRow row;
    while ((row = cursor.NextRow()) != null)
    {
        //处理逻辑
    }
}

posted on 2021-11-04 11:01  鹿果一夏  阅读(260)  评论(0编辑  收藏  举报

导航