版本: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;
}