MemberwiseClone()的方法是什么?

Sye*_*Ali 48 c# design-patterns prototype clone

我对下面的代码感到困惑,

Developer devCopy = (Developer)dev.Clone();
Run Code Online (Sandbox Code Playgroud)

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

*/
Run Code Online (Sandbox Code Playgroud)

Boz*_*zho 65

因为这个方法MemberwiseClone()是为你做的.请参阅文档

MemberwiseClone方法通过创建新对象,然后将当前对象的非静态字段复制到新对象来创建浅表副本.如果字段是值类型,则执行字段的逐位复制.如果字段是引用类型,则复制引用但不引用引用的对象; 因此,原始对象及其克隆引用相同的对象.

每当你看到一个你不知道的方法时,你可以追踪谁已经声明它(在Visual Studio中,我猜),然后查看它的文档.这使得事情在大多数时候都非常明显.


sup*_*cat 14

该函数MemberwiseClone创建一个新对象,其字段是原始结构中那些字段的逐位副本.它是任何可继承类的必要部分,它允许克隆而不使用Reflection或序列化,但它只是整个难题的一小部分.

如果您希望允许在可继承类中进行克隆,则应定义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();}
Run Code Online (Sandbox Code Playgroud)

这将允许一个类可能有一些可以克隆的后代和一些不能克隆的情况.那些可以克隆的可以暴露公共克隆方法(应该链接到BaseClone<theirOwnType>).需要基类型可克隆衍生物的方法可以使用类型参数ICloneable<theBaseType>; 这将允许他们接受任何基类型的可克隆衍生物,即使并非所有这些衍生物都共享一个共同的基类.


Mas*_*ian 13

副本有两种类型:ShallowCopyDeepCopy

ShallowCopy复制所有value type成员和nonstatic字段,这正是所做MemberwiseClone()的。

但价值观呢reference type?这是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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 在 `DeepCopy()` 方法中调用 `clone.Name = String.Copy(Name);` 有什么用?ASAIK 字符串是不可变的,因此即使它是引用类型,在克隆的 Person 对象中也不应该有共享相同引用的 rist,因为在一个 Person 实例上更改 Name 不会影响另一个实例,对吧? (2认同)