【发布时间】:2010-11-11 08:59:10
【问题描述】:
我有一个名为 Employee 的类,其中有 3 个属性名为 ID,Name,Dept。我需要实现Copy 和Clone 方法吗?当我使用Copy 或Clone 方法时,我需要避免强制转换吗?我该怎么做呢?
示例:与DataTable 相同,具有DataTable.Copy() 和DataTable.Clone()。
【问题讨论】:
我有一个名为 Employee 的类,其中有 3 个属性名为 ID,Name,Dept。我需要实现Copy 和Clone 方法吗?当我使用Copy 或Clone 方法时,我需要避免强制转换吗?我该怎么做呢?
示例:与DataTable 相同,具有DataTable.Copy() 和DataTable.Clone()。
【问题讨论】:
你需要实现IClonable接口并提供clone方法的实现。如果你想避免强制转换,不要实现这个。
一个简单的深度克隆方法可能是将对象序列化到内存然后反序列化它。您的类中使用的所有自定义数据类型都需要使用 [Serializable] 属性进行序列化。对于克隆,您可以使用类似
public MyClass Clone()
{
MemoryStream ms = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, this);
ms.Position = 0;
object obj = bf.Deserialize(ms);
ms.Close();
return obj as MyClass;
}
如果您的类只有value types,那么您可以使用copy constructor 或只是将值分配给 Clone 方法中的新对象。
【讨论】:
您是否必须使用 ICloneable 接口,或者仅在通用接口中定义两个名为 Clone 和 Copy 的方法就足够了?
public class YourClass : ICloneable<YourClass>
{
// Constructor logic should be here
public YourClass Copy() { return this; }
public YourClass Clone() { return new YourClass(ID, Name, Dept); }
}
interface IClonable<T>
{
T Copy();
T Clone();
}
还是我误会了什么?
我想说的是,您不必让它变得更复杂吗?如果您需要您的对象符合某种要求,如果 .Net 框架中指定的对象对于这种情况来说过于复杂,您可以自己编写它。您还应该定义与Clone 和Copy 的区别,即它们对您意味着什么?我知道有几个站点指定Clone 是深拷贝,Copy 是浅拷贝。
【讨论】:
CopyClone() 方法以合并它(以及它调用的构造函数)。如果要调用构造函数,而不是传递离散字段,则应传递整个对象,即:return new YourClass(this)
MapRow 方法:blog.tomasjansson.com/2010/10/generic-mapper-for-datareader 以了解包含/排除如何工作的示例。
你的意思是,如何实现 ICloneable.Clone() 并让它返回类本身的类型。
public class MyType : ICloneable
{
public MyType Clone() //called directly on MyType, returns MyType
{
return new MyType(/* class-dependant stuff goes here */);
}
object ICloneable.Clone() // called through ICloneable interface, returns object
{
return Clone();
}
}
【讨论】:
【讨论】:
我经常看到建议将复制构造函数作为克隆方法的替代方法,但除了密封类之外,其行为非常不同。如果我有一个类型 Car,它只支持属性 VIN、BodyColor 和 BodyStyle,以及一个衍生类型 FancyCar,它也支持 InteriorFabric 和 SoundSystem,那么接受 Car 类型对象并使用 Car 复制构造函数复制它的代码将结束开一辆车。如果将 FancyCar 传递给此类代码,则生成的“副本”将是一辆新车,其 VIN、BodyColor 和 BodyStyle 与原车匹配,但没有任何 InteriorFabric 或 SoundSystem。相比之下,代码接受 Car 并在其上使用克隆方法,将 FancyCar 传递给代码将导致 FancyCar 生成。
除非想要使用反射,否则任何克隆方法都必须在其基础上调用 base.MemberwiseClone。由于 MemberwiseClone 不是虚拟方法,我建议定义一个受保护的虚拟克隆方法;您可能还希望通过定义具有相同名称的受保护范围的虚拟嵌套类来防止任何子类调用 MemberwiseClone(因此,如果后代类尝试调用 base.MemberwiseClone,它不会被解释为对虚拟类)。
【讨论】:
这里是一个例子:
namespace XXX
{
[Serializable]
public class ItemChecklist : ICloneable
{
// [...here properties, attributes, etc....]
object ICloneable.Clone()
{
return this.Clone();
}
public ItemChecklist Clone()
{
return (ItemChecklist)this.MemberwiseClone();
}
}
}
即如果您使用此函数,您将在“itemAdd”中拥有对象“itemTemp”及其所有值的完整副本。
ItemChecklist itemAdd = itemTemp.Clone();
【讨论】: