ArcEngine的COM对象在.NET中的释放问题

ae的com对象是需要释放的,不然就可能会锁住一些基础设备(如mdb文件等),这里研究了一下ae锁mdb的情况

释放方法一般是,Marshal.ReleaseComObject或Marshal.FinalReleaseComObject

但要在什么时候释放com对象呢,这就需要了解dotnet跟com交互的实现方法:运行库可调用包装(RCW)

每次将 COM 接口指针映射到该运行时可调用包装时,此引用计数都将递增。这是msdn中Marshal.ReleaseComObject 方法 描述里的一句话。那这句话是什么意思呢,什么样的操作才会导致将COM接口指针映射到运行时可调用包装。做了一个简单的实验,打开一个workspace,并打开一个featureclass,使用方法Marshal.ReleaseComObject释放COM,查看引用计数(不知道如何查看引用计数,只能通过Marshal.ReleaseComObject方法),以此来判断是否执行了将COM接口指针映射到运行时可调用包操作。

情况一:新声明一个workspace局部变量,将原来的workspace值赋给新变量,释放workspace,查看workspace引用计数

IWorkspaceFactory wsf = new AccessWorkspaceFactoryClass();
IWorkspace ws = wsf.OpenFromFile(mdbPath, 0);
IFeatureClass fls = ((IFeatureWorkspace)ws).OpenFeatureClass(featureClassName);
IWorkspace ws1 = ws;
int i = Marshal.ReleaseComObject(ws);

i的值为0。

情况二:新声明一个workspace局部变量,通过IDataset.Workspace属性给新变量赋值,释放workspace,查看workspace引用计数

IWorkspaceFactory wsf = new AccessWorkspaceFactoryClass();
IWorkspace ws = wsf.OpenFromFile(mdbPath, 0);
IFeatureClass fls = ((IFeatureWorkspace)ws).OpenFeatureClass(featureClassName);
IWorkspace ws1 = ((IDataset)fls).Workspace;
int i = Marshal.ReleaseComObject(ws);

i的值为1。

我大胆的得出结论(有可能不对):将COM接口指针映射到运行时可调用包装操作是在调用执行com对象方法并返回值时才会发生。

情况三:在一个方法里面打开featureclass,不释放workspace,新声明一个workspace局部变量,通过IDataset.Workspace属性给新变量负责,释放workspace,查看workspace引用计数

       private IFeatureClass getFclss(string path, string featureClassName)
        {
            IWorkspaceFactory wsf = new AccessWorkspaceFactoryClass();
            IWorkspace ws = wsf.OpenFromFile(path, 0);
            return ((IFeatureWorkspace)ws).OpenFeatureClass(featureClassName);
        }
        IFeatureClass fls = getFclss(mdbPath, featureClassName);
        IWorkspace ws = ((IDataset)fls).Workspace;
        int i = Marshal.ReleaseComObject(ws);

i的值为1。

情况四:跟情况三类似,不同的是调用了GC.Collect方法

       IFeatureClass fls = getFclss(mdbPath, featureClassName);
       GC.Collect();
        IWorkspace ws = ((IDataset)fls).Workspace;
       int i = Marshal.ReleaseComObject(ws);

i的值为0。

比较情况三跟情况四,可以得出结论,释放COM对象在dotnet中的映射对象的时候,引用计数会减一

情况五:调用情况三的获取featureclass的方法,释放得到的featureclass,删除mdb文件

IFeatureClass fls = getFclss(mdbPath, featureClassName);
Marshal.ReleaseComObject(fls);
File.Delete(mdbPath);

得到“文件“。。。”正由另一进程使用,因此该进程无法访问该文件。”的异常。

情况六:修改getFclss方法,在方法内释放掉worksapce,再像情况五一样操作

        private IFeatureClass getFclss(string path, string featureClassName)
        {
            IWorkspaceFactory wsf = new AccessWorkspaceFactoryClass();
            IWorkspace ws = wsf.OpenFromFile(path, 0);
            try
            {
                return ((IFeatureWorkspace)ws).OpenFeatureClass(featureClassName);
            }
            finally
            {
                Marshal.ReleaseComObject(ws);
            }
        }

这时可以删除掉文件。

情况七:调用情况六修改后的getFclss,不释放featureclass,直接删除文件

IFeatureClass fls = getFclss(mdbPath, featureClassName);
File.Delete(mdbPath);

得到情况五一样的异常。

情况八:调用情况六修改后的getFclss,新声明一个workspace局部变量,通过IDataset.Workspace属性给新变量赋值。

IFeatureClass fls = getFclss(mdbPath, featureClassName);
IWorkspace ws = ((IDataset)fls).Workspace;

这时得到的ws是可以查看属性的,释放后的com对象查看属性会得到提示为“COM 对象与其基础 RCW 分开后就不能再使用。”的异常。

情况九:workspace打开ifeatureclass2次

            IWorkspaceFactory wsf = new AccessWorkspaceFactoryClass();
            IWorkspace ws = wsf.OpenFromFile(mdbPath, 0);
            IFeatureClass fcls= ((IFeatureWorkspace)ws).OpenFeatureClass(featureClassName);
            IFeatureClass fcls1 = ((IFeatureWorkspace)ws).OpenFeatureClass(featureClassName);
            int i = Marshal.ReleaseComObject(fcls);

i的值为1。

那么对于访问COM对象属性的属性的情况会是怎么样呢。

情况十:创建getDataset方法,跟新的getFclss一样,只是返回的是IDataset,访问IDataset.Workspace,再访问IDataset.Workspace.PathName,释放workspace,查看引用计数

       private IDataset getDataset(string path, string featureClassName)
        {
            IWorkspaceFactory wsf = new AccessWorkspaceFactoryClass();
            IWorkspace ws = wsf.OpenFromFile(path, 0);
            try
            {
                return ((IFeatureWorkspace)ws).OpenFeatureClass(featureClassName) as IDataset;
            }
            finally
            {
                Marshal.ReleaseComObject(ws);
            }
        }
        IDataset ds = getDataset(mdbPath, featureClassName);
            IWorkspace ws = ds.Workspace;
            string s = ds.Workspace.PathName;
            int i = Marshal.ReleaseComObject(ws);

i的值为1。

所以,为了避免有的对象释放漏掉,最好不要使用IDataset.Workspace.PathName这种写法。

ae的com对象是需要释放的,不然就可能会锁住一些基础设备(如mdb文件等),这里研究了一下ae锁mdb的情况

释放方法一般是,Marshal.ReleaseComObject或Marshal.FinalReleaseComObject

但要在什么时候释放com对象呢,这就需要了解dotnet跟com交互的实现方法:运行库可调用包装(RCW)

每次将 COM 接口指针映射到该运行时可调用包装时,此引用计数都将递增。这是msdn中Marshal.ReleaseComObject 方法 描述里的一句话。那这句话是什么意思呢,什么样的操作才会导致将COM接口指针映射到运行时可调用包装。做了一个简单的实验,打开一个workspace,并打开一个featureclass,使用方法Marshal.ReleaseComObject释放COM,查看引用计数(不知道如何查看引用计数,只能通过Marshal.ReleaseComObject方法),以此来判断是否执行了将COM接口指针映射到运行时可调用包操作。

情况一:新声明一个workspace局部变量,将原来的workspace值赋给新变量,释放workspace,查看workspace引用计数

IWorkspaceFactory wsf = new AccessWorkspaceFactoryClass();
IWorkspace ws = wsf.OpenFromFile(mdbPath, 0);
IFeatureClass fls = ((IFeatureWorkspace)ws).OpenFeatureClass(featureClassName);
IWorkspace ws1 = ws;
int i = Marshal.ReleaseComObject(ws);

i的值为0。

情况二:新声明一个workspace局部变量,通过IDataset.Workspace属性给新变量赋值,释放workspace,查看workspace引用计数

IWorkspaceFactory wsf = new AccessWorkspaceFactoryClass();
IWorkspace ws = wsf.OpenFromFile(mdbPath, 0);
IFeatureClass fls = ((IFeatureWorkspace)ws).OpenFeatureClass(featureClassName);
IWorkspace ws1 = ((IDataset)fls).Workspace;
int i = Marshal.ReleaseComObject(ws);

i的值为1。

我大胆的得出结论(有可能不对):将COM接口指针映射到运行时可调用包装操作是在调用执行com对象方法并返回值时才会发生。

情况三:在一个方法里面打开featureclass,不释放workspace,新声明一个workspace局部变量,通过IDataset.Workspace属性给新变量负责,释放workspace,查看workspace引用计数

       private IFeatureClass getFclss(string path, string featureClassName)
        {
            IWorkspaceFactory wsf = new AccessWorkspaceFactoryClass();
            IWorkspace ws = wsf.OpenFromFile(path, 0);
            return ((IFeatureWorkspace)ws).OpenFeatureClass(featureClassName);
        }
        IFeatureClass fls = getFclss(mdbPath, featureClassName);
        IWorkspace ws = ((IDataset)fls).Workspace;
        int i = Marshal.ReleaseComObject(ws);

i的值为1。

情况四:跟情况三类似,不同的是调用了GC.Collect方法

       IFeatureClass fls = getFclss(mdbPath, featureClassName);
       GC.Collect();
        IWorkspace ws = ((IDataset)fls).Workspace;
       int i = Marshal.ReleaseComObject(ws);

i的值为0。

比较情况三跟情况四,可以得出结论,释放COM对象在dotnet中的映射对象的时候,引用计数会减一

情况五:调用情况三的获取featureclass的方法,释放得到的featureclass,删除mdb文件

IFeatureClass fls = getFclss(mdbPath, featureClassName);
Marshal.ReleaseComObject(fls);
File.Delete(mdbPath);

得到“文件“。。。”正由另一进程使用,因此该进程无法访问该文件。”的异常。

情况六:修改getFclss方法,在方法内释放掉worksapce,再像情况五一样操作

        private IFeatureClass getFclss(string path, string featureClassName)
        {
            IWorkspaceFactory wsf = new AccessWorkspaceFactoryClass();
            IWorkspace ws = wsf.OpenFromFile(path, 0);
            try
            {
                return ((IFeatureWorkspace)ws).OpenFeatureClass(featureClassName);
            }
            finally
            {
                Marshal.ReleaseComObject(ws);
            }
        }

这时可以删除掉文件。

情况七:调用情况六修改后的getFclss,不释放featureclass,直接删除文件

IFeatureClass fls = getFclss(mdbPath, featureClassName);
File.Delete(mdbPath);

得到情况五一样的异常。

情况八:调用情况六修改后的getFclss,新声明一个workspace局部变量,通过IDataset.Workspace属性给新变量赋值。

IFeatureClass fls = getFclss(mdbPath, featureClassName);
IWorkspace ws = ((IDataset)fls).Workspace;

这时得到的ws是可以查看属性的,释放后的com对象查看属性会得到提示为“COM 对象与其基础 RCW 分开后就不能再使用。”的异常。

情况九:workspace打开ifeatureclass2次

            IWorkspaceFactory wsf = new AccessWorkspaceFactoryClass();
            IWorkspace ws = wsf.OpenFromFile(mdbPath, 0);
            IFeatureClass fcls= ((IFeatureWorkspace)ws).OpenFeatureClass(featureClassName);
            IFeatureClass fcls1 = ((IFeatureWorkspace)ws).OpenFeatureClass(featureClassName);
            int i = Marshal.ReleaseComObject(fcls);

i的值为1。

那么对于访问COM对象属性的属性的情况会是怎么样呢。

情况十:创建getDataset方法,跟新的getFclss一样,只是返回的是IDataset,访问IDataset.Workspace,再访问IDataset.Workspace.PathName,释放workspace,查看引用计数

       private IDataset getDataset(string path, string featureClassName)
        {
            IWorkspaceFactory wsf = new AccessWorkspaceFactoryClass();
            IWorkspace ws = wsf.OpenFromFile(path, 0);
            try
            {
                return ((IFeatureWorkspace)ws).OpenFeatureClass(featureClassName) as IDataset;
            }
            finally
            {
                Marshal.ReleaseComObject(ws);
            }
        }
        IDataset ds = getDataset(mdbPath, featureClassName);
            IWorkspace ws = ds.Workspace;
            string s = ds.Workspace.PathName;
            int i = Marshal.ReleaseComObject(ws);

i的值为1。

所以,为了避免有的对象释放漏掉,最好不要使用IDataset.Workspace.PathName这种写法。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值