释放ArcGIS Engine的Com组件的资源
问题:
使用ArcGIS Engine 的打开或读取数据时,由于资源未释放,而导致数据文件一直被占用。
如下代码:
//using ESRI.ArcGIS.esriSystem;
//using ESRI.ArcGIS.Geodatabase;
//using ESRI.ArcGIS.DataSourcesGDB;
//打开GDB中要素类
public static void OpenGDBFeatureClass(string path, string name)
{
IWorkspaceFactory pWorkspaceFactory = new FileGDBWorkspaceFactoryClass(); //GDB工作空间工厂类
IFeatureWorkspace pFeatureWorkspace = pWorkspaceFactory.OpenFromFile(path, 0) as IFeatureWorkspace; //打开GDB工作空间
IFeatureClass pFeatureClass = pFeatureWorkspace.OpenFeatureClass(name); //打开要素类
//遍历所有要素类
IFeatureCursor pFeatureCursor = pFeatureClass.Search(null, false);
IFeature pFeature = pFeatureCursor.NextFeature();
while (pFeature != null)
{
//TODO : do something
pFeature = pFeatureCursor.NextFeature();
}
}
以上代码实现打开GDB中要素类,并遍历所有要素的功能。代码存在着一些缺陷,COM资源pFeatureWorkspace、pFeatureClass和IFeatureCursor由于未释放,即使以上函数执行结束,GDB仍会一直处于占用状态,直到程序完全关闭才会释放。
解决方法:
1、通过System.Runtime.InteropServices释放COM资源
使用命名空间using System.Runtime.InteropServices,修改以上代码后:
//using ESRI.ArcGIS.esriSystem;
//using ESRI.ArcGIS.Geodatabase;
//using ESRI.ArcGIS.DataSourcesGDB;
//using System.Runtime.InteropServices;
//打开GDB中要素类
public static void OpenGDBFeatureClass(string path, string name)
{
IWorkspaceFactory pWorkspaceFactory = new FileGDBWorkspaceFactoryClass();
IFeatureWorkspace pFeatureWorkspace = pWorkspaceFactory.OpenFromFile(path, 0) as IFeatureWorkspace; //打开GDB工作空间
IFeatureClass pFeatureClass = pFeatureWorkspace.OpenFeatureClass(name); //打开要素类
//遍历所有要素类
IFeatureCursor pFeatureCursor = pFeatureClass.Search(null, false);
IFeature pFeature = pFeatureCursor.NextFeature();
while (pFeature != null)
{
//TODO : do something
pFeature = pFeatureCursor.NextFeature();
}
//释放资源
System.Runtime.InteropServices.Marshal.ReleaseComObject(pFeatureCursor);
System.Runtime.InteropServices.Marshal.ReleaseComObject(pFeatureClass);
System.Runtime.InteropServices.Marshal.ReleaseComObject(pFeatureWorkspace);
}
2、通过ComReleaser释放Com资源
ComReleaser是ArcGIS Engine用来释放Com资源的类,类的实现位于命名空间ESRI.ArcGIS.ADF.Connection.Local中。因此需先引用ESRI.ArcGIS.ADF.Connection.Local.dll,然后使用using ESRI.ArcGIS.ADF语句使用命名空间。
注意:C#程序的目标框架需要改为.NET Framework 4.0,不然可能无法正常使用ComReleaser。
改进后的代码:
//using ESRI.ArcGIS.esriSystem;
//using ESRI.ArcGIS.Geodatabase;
//using ESRI.ArcGIS.DataSourcesGDB;
//using ESRI.ArcGIS.ADF;
//打开GDB中要素类
public static void OpenGDBFeatureClass(string path, string name)
{
using (ComReleaser comReleaser = new ComReleaser())
{
IWorkspaceFactory pWorkspaceFactory = new FileGDBWorkspaceFactoryClass();
IFeatureWorkspace pFeatureWorkspace = pWorkspaceFactory.OpenFromFile(path, 0) as IFeatureWorkspace; //打开GDB工作空间
comReleaser.ManageLifetime(pFeatureWorkspace); //延迟释放资源
IFeatureClass pFeatureClass = pFeatureWorkspace.OpenFeatureClass(name); //打开要素类
comReleaser.ManageLifetime(pFeatureClass); //延迟释放资源
//遍历所有要素类
IFeatureCursor pFeatureCursor = pFeatureClass.Search(null, false);
comReleaser.ManageLifetime(pFeatureCursor); //延迟释放资源
IFeature pFeature = pFeatureCursor.NextFeature();
while (pFeature != null)
{
//TODO : do something
pFeature = pFeatureCursor.NextFeature();
}
}
}
对比:
两种方法都可以用于释放Com资源,但是第二种方法更安全,也是ArcGIS Engine官方推荐一种释放资源的方式;因为一旦程序抛出异常,或者函数提前结束,第一种方法就无法执行释放语句,但第二种方法却可以保证正常释放资源。