ArcObjects编程方法(五):对象复制的实现
版本:ArcGIS 10
ArcGIS支持IClone接口的对象,可以通过Clone()方法复制对象,其过程比创建新变量要复杂。一下展现创建两个指向同一个对象的变量:
[C#]
IPoint pointOne = new PointClass(); IPoint pointTwo = pointOne;
以下展现通过IClone接口复制对象:
[C#]
IClone clone = pointOne as IClone; pointTwo = clone.Clone()as IPoint;
深复制(deep clone)和浅复制(shallow clone)
如果被复制的对象只包含值类型的数据,则复制过程比较简单,复制体将包含所有被复制对象的信息。但是,当被复制对象包含引用类型的数据时,复制分为深度复制和初级复制。深复制将创建复制对象及其引用指向的对象,浅复制只会复制其引用。过程如下图:
深复制例子:当图形单元被复制,其几何属性和样式属性也将被复制,复制体完全独立于以前的对象。
浅复制例子:在一个要素类,一个几何要素被复制,其空间引用属性指向同一对象,用来定义同一坐标系。
因此在复制对象时,要根据具体需要选择复制的方式,特别是对象包含引用数据的时候。
复制的实现
一般有两种方式实现复制。一种是被复制对象创建实例,并将所有成员信息复制到新建的实例。另一种方式是根据对象持续保存的特性,先将对象临时保存在内存流中,再从内存流中读取对象,这要求对象实现IPersist接口和IPersistStream接口。
对象实现Clone方法:
[C#]
public IClone Clone() { ClonableObjClass obj = new ClonableObjClass(); obj.Assign(this); return (IClone)obj; }
Assign方法:
public void Assign(IClone src) { //1. 确认引用非空 if (null == src) { throw new COMException("Invalid object."); } //2. 类型符合要求 if (!(src is ClonableObjClass)) { throw new COMException("Bad object type."); } //3. 将src的属性复制给现在的实例 ClonableObjClass srcClonable = (ClonableObjClass)src; m_name = srcClonable.Name; m_version = srcClonable.Version; m_ID = srcClonable.ID; //浅复制 m_spatialRef = srcClonable.SpatialReference; }
上述的Assign只是把值赋给新的实例实现浅复制,也可以通过如下代码实现深复制:
[C#]
public void Assign(IClone src) { //1. 确认引用非空 if (null == src) { throw new COMException("Invalid object."); } //2. 类型符合要求 if (!(src is ClonableObjClass)) { throw new COMException("Bad object type."); } //3. 将src的属性复制给现在的实例 ClonableObjClass srcClonable = (ClonableObjClass)src; m_name = srcClonable.Name; m_version = srcClonable.Version; m_ID = srcClonable.ID; //深复制 IClone cloned = srcClonable.SpatialReference as IClone; if (null != cloned) { m_spatialRef = (ISpatialReference)cloned.Clone(); } }
通过ObjectCopy进行深复制:
[C#]
//通过ObjectCopy深复制SpatialReference if (null == srcClonable.SpatialReference) m_spatialRef = null; else { IObjectCopy objectCopy = new ObjectCopyClass(); object obj = objectCopy.Copy((object)srcClonable.SpatialReference); m_spatialRef = (ISpatialReference)obj; }
IsEqual方法判断被复制的实例和新实例的成员信息是否相同:
[C#]
public bool IsEqual(IClone other) { //1. 非空 if (null == other) throw new COMException("Invalid object."); //2. 类型合法 if (!(other is ClonableObjClass)) throw new COMException("Bad object type."); ClonableObjClass otherClonable = (ClonableObjClass)other; //测试属性是否相等 if (otherClonable.Version == m_version && otherClonable.Name == m_name && otherClonable.ID == m_ID && ((IClone)otherClonable.SpatialReference).IsEqual ((IClone)m_spatialRef)) )return true; return false; }
IsIdentical方法判断两者是否指向内存中的同一对象:[C#]
public bool IsIdentical(IClone other) { //1.非空 if (null == other) throw new COMException("Invalid object."); //2. 类型合法 if (!(other is ClonableObjClass)) throw new COMException("Bad object type."); //3. 判断 if ((ClonableObjClass)other == this) return true; return false; }