atravellers

导航

C# 使用SuperMap控件需要千万注意的地方(转载)

 C# 使用SuperMap控件需要千万注意的地方

讨论SuperMap前,我们衷心的希望微软能够改进垃圾回收器,更加智能的帮助开发人员释放对象。
首先看下传统的COM对象与.NET框架对象模型的创建与释放的不同:
(1)、COM对象的客户必须自己管理COM对象的生存期,而.NET对象的生存期由CLR(Common Language Runtime)来管理,即通过GC(Garbage Collection)机制自动回收。
(2)、COM对象的客户通过指针引用COM对象,对象在内存中的位置是不变的,而.NET对象在内存中的驻留由.NET框架执行环境(execution environment)来管理,对象在内存中的位置是可变的,比如出于优化性能的考虑,同时会更新所有对对象的引用。这一点也是以CLR中不使用指针为前提的。
简单的说.com客户每次引用对象的时候,就调用
          IUnKnown->AddRef(),而每次释放对象的时候,就调用
          IUnKnown->Release(),一旦引用计数达到零,就释放实例。
如何在.NET中Release彻底释放呢?非常幸运,在.net中允许程序员显式地自己调用com的Release方法,这个方法叫做System.Runtime.InteropServices.Marshal.ReleaseComObject。

现在来说SuperMap,根本上讲SuperMap的控件在.NET中都是COM对象,这次我们讨论的要点就是如何写才能完全彻底的释放COM对象。先来看段代码:
private void axSuperMap1_Tracked(object sender, EventArgs e)
{
soDatasetVector _soDatasetVector = SuperWorkspace.Datasources[0].Datasets[0] as soDatasetVector;
soRecordset _soRecordset = _soDatasetVector.Query("1=2", true, null, "");
if (_soRecordset.AddNew(axSuperMap1.TrackedGeometry, null) == -1)
{
       MessageBox.Show("添加数据失败");
}
System.Runtime.InteropServices.Marshal.ReleaseComObject(_soRecordset);
_soRecordset = null;
System.Runtime.InteropServices.Marshal.ReleaseComObject(_soDatasetVector);
_soDatasetVector = null;
}
这段代码看似相当的简洁 风格很棒。但是实际上却没有释放完全。
现在我们就来说标题上的“千万千万”的地方。
对于一些隐含返回的对象,也要这样调用ReleaseComObject才能将其正确释放,并保证其正常运作。
对于一些隐含返回的对象,也要这样调用ReleaseComObject才能将其正确释放,并保证其正常运作。
对于一些隐含返回的对象,也要这样调用ReleaseComObject才能将其正确释放,并保证其正常运作。

现在我们来看看上面这段代码的释放完全的写法:
private void axSuperMap1_Tracked(object sender, EventArgs e)
{
soDataSources _soDataSources = SuperWorkspace.Datasources;
soDataSource _soDataSource = SuperWorkspace.Datasources[0];
soDatasets _soDatasets=_soDataSource.Datasets;
soDataset _Dataset = _soDatasets[0];
soDatasetVector _soDatasetVector = _Dataset as soDatasetVector;
soGeometry _soGeometry = axSuperMap1.TrackedGeometry;
soRecordset _soRecordset = _soDatasetVector.Query("1=2", true, null, "");
if (_soRecordset.AddNew(_soGeometry, null) == -1)
{
       MessageBox.Show("添加数据失败");
}
System.Runtime.InteropServices.Marshal.ReleaseComObject(_soGeometry);
_soGeometry = null;
System.Runtime.InteropServices.Marshal.ReleaseComObject(_soRecordset);
_soRecordset = null;
System.Runtime.InteropServices.Marshal.ReleaseComObject(_soDatasetVector);
_soDatasetVector = null;
System.Runtime.InteropServices.Marshal.ReleaseComObject(_Dataset);
_Dataset = null;
System.Runtime.InteropServices.Marshal.ReleaseComObject(_soDatasets);
_soDatasets = null;
System.Runtime.InteropServices.Marshal.ReleaseComObject(_soDataSource);
_soDataSource = null;
System.Runtime.InteropServices.Marshal.ReleaseComObject(_soDataSources);
_soDataSources = null;
}

你没看错,其实我也很郁闷。这样写的确很弱,很委琐。
但是千万记住,如果不想你写的产品在你想不到的时候弹出“System.AccessViolationException: 尝试读取或写入受保护的内存。这通常指示其他内存已损坏。”的错误,还是老实再老实的用这很弱的写法吧。
转载自http://www.gisbox.cn/thread-156-1-1.html

posted on 2010-01-22 09:13  zhaojp  阅读(1482)  评论(0编辑  收藏  举报