我对下面的代码感到困惑,
Developer devCopy = (Developer)dev.Clone();
Developer类的克隆方法只是创建一个Employee克隆,然后是开发人员如何获得另一个开发人员克隆。
public abstract class Employee
{
public abstract Employee Clone();
public string Name { get; set; }
public string Role { get; set; }
}
public class Typist : Employee
{
public int WordsPerMinute { get; set; }
public override Employee Clone()
{
return (Employee)MemberwiseClone();
}
public override string ToString()
{
return string.Format("{0} - {1} - {2}wpm", Name, Role, WordsPerMinute);
}
}
public class Developer : Employee
{
public string PreferredLanguage { get; set; }
public override Employee Clone()
{
return (Employee)MemberwiseClone();
}
public override string ToString()
{
return string.Format("{0} - {1} - {2}", Name, Role, PreferredLanguage);
}
}
Developer dev = new Developer();
dev.Name = "Bob";
dev.Role = "Team Leader";
dev.PreferredLanguage = "C#";
Developer devCopy = (Developer)dev.Clone();
devCopy.Name = "Sue";
Console.WriteLine(dev);
Console.WriteLine(devCopy);
/* OUTPUT
Bob - Team Leader - C#
Sue - Team Leader - C#
*/
Typist typist = new Typist();
typist.Name = "Kay";
typist.Role = "Typist";
typist.WordsPerMinute = 120;
Typist typistCopy = (Typist)typist.Clone();
typistCopy.Name = "Tim";
typistCopy.WordsPerMinute = 115;
Console.WriteLine(typist);
Console.WriteLine(typistCopy);
/* OUTPUT
Kay - Typist - 120wpm
Tim - Typist - 115wpm
*/
答案 0 :(得分:60)
因为方法MemberwiseClone()
正在为您执行此操作。见the documentation
MemberwiseClone方法通过创建新对象,然后将当前对象的非静态字段复制到新对象来创建浅表副本。如果字段是值类型,则执行字段的逐位复制。如果字段是引用类型,则复制引用但不引用引用的对象;因此,原始对象及其克隆引用相同的对象。
每当你看到一个你不知道的方法时,你就可以追踪已经声明它的人(我想在Visual Studio中),然后再查看它的文档。这使得事情在大多数时候都很明显。
答案 1 :(得分:12)
函数MemberwiseClone
创建一个新对象,其字段是原始结构中那些字段的逐位副本。它是任何可继承类的必要部分,它允许克隆而不使用反射或序列化,但它只是整个难题的一小部分。
如果您希望允许在可继承类中进行克隆,则应定义protected virtual T BaseClone<T>()
克隆方法;从Object
下降的基级类应该调用base.MemberwiseClone
;所有其他类应使用base.BaseClone<T>
来获取新实例,然后将任何可变克隆字段替换为原始对象中克隆的克隆。
我还建议定义以下接口:
interface ISelf<out T> {T Self();}
interface ICloneable<out T> : ISelf<T> {T Clone();}
这将允许一个类可能有一些可以克隆的后代而一些不能克隆的情况。那些可以克隆的方法可以暴露公共克隆方法(应该链接到BaseClone<theirOwnType>
)。需要基类型可克隆衍生物的方法可以使用ICloneable<theBaseType>
类型的参数;这将允许他们接受任何基类型的可克隆衍生物,即使并非所有这些衍生物都共享一个共同的基类。
答案 2 :(得分:1)
有两种类型的副本:ShallowCopy
和DeepCopy
。
ShallowCopy
复制所有valuetype
成员和nonstatic
字段,而这正是MemberwiseClone()
的作用。
但是referencetype
值呢?这就是使用DeepCopy
的地方。通过使用DeepCopy
,不会复制引用,但是将从引用中生成一个新对象。
请注意,通过使用ShallowCopy
,将复制参考地址,因此复制的参考地址指向同一对象。因此,更改一个对象会更改所有副本。
请考虑以下示例:
class Person
{
public int Age { get; set; }
public string Name { get; set; }
public DateTime BirthDate { get; set; }
public IdInfo IdInfo { get; set; }
public Person ShallowCopy()
{
return this.MemberwiseClone() as Person;
}
public Person DeepCopy()
{
var clone = this.MemberwiseClone() as Person;
clone.Name = String.Copy(Name);
clone.IdInfo = new IdInfo(IdInfo.IdNumber);
return clone;
}
}
class IdInfo
{
public int IdNumber { get; set; }
public IdInfo(int idNumber)
{
this.IdNumber = idNumber;
}
}