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: 尝试读取或写入受保护的内存。这通常指示其他内存已损坏。”的错误,还是老实再老实的用这很弱的写法吧。 |