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)
{
//处理逻辑
}
}