如何克隆对象

PiZ*_*zL3 51 c# object

当我做了某乙以下..任何人修改一个(我以为这样做会克隆从人,将B).我也不知道如果更改Person a将在链接后更改Person b.由于我的代码现在,我只能在一个方向看到这个.

Person a = new Person() { head = "big", feet = "small" };
Person b = a; 

b.head = "small"; //now a.head = "small" too   
Run Code Online (Sandbox Code Playgroud)

现在如果我这样做了.人a变得完全分开.

Person b = new Person() { head = a.head, feet = a.feet };
Run Code Online (Sandbox Code Playgroud)

现在,将此行为与C#中的其他内容进行比较时,这种方法很有意义.但是,对于大型物体,这可能会非常烦人.

有没有办法简化这个?

如:

Person b = a.Values;

She*_*Pro 64

您正在寻找的是克隆.您需要实现IClonable然后进行克隆.

例:

class Person() : ICloneable
{
    public string head;
    public string feet; 

    #region ICloneable Members

    public object Clone()
    {
        return this.MemberwiseClone();
    }

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

然后您可以简单地调用Clone方法来执行ShallowCopy(在此特定情况下也是一个DeepCopy)

Person a = new Person() { head = "big", feet = "small" };
Person b = (Person) a.Clone();  
Run Code Online (Sandbox Code Playgroud)

您可以使用Object类的MemberwiseClone方法进行克隆.

  • 不要使用IClonable:http://blogs.msdn.com/b/brada/archive/2003/04/09/49935.aspx (5认同)
  • @Robert Levy:我知道当你在课堂上有成员参考类型时,浅拷贝和深拷贝之间会出现差异. (4认同)
  • @RobertLevy这个链接没有任何连贯点,只是很久以前有人在互联网上感到沮丧. (3认同)
  • @jpaugh 在 5 年前博客格式被破坏之前更容易阅读,但它基本上是微软的一个帖子,他写了框架设计指南,发布了一个指南,IClonable 不应该被使用,因为它的合同是模棱两可的 (2认同)

Ree*_*sey 42

有没有办法简化这个?

不,不是真的.您需要创建一个新实例,以避免原始文件影响"副本".有几种选择:

  1. 如果您的类型是a struct,而不是a class,则它将按值复制(而不是仅仅复制对实例的引用).这将给它您所描述的语义,但是有许多其他的副作用,往往不甚理想,因此不推荐用于任何可变类型(这显然是,或者这不会是一个问题!)

  2. 在您的类型上实现"克隆"机制.这可以是ICloneable甚至只是一个构造函数,它接受一个实例并从中复制值.

  3. 使用反射,MemberwiseClone,或类似的跨复制所有值,所以你不必编写代码来做到这一点.这有潜在的问题,特别是如果您有包含非简单类型的字段.

  • 不建议实施ICloneable.它没有通用版本.克隆将不具有原始类型,但将是object类型.此外,只能从克隆方法写入只读字段.编写一个以原始为参数的构造函数更好. (2认同)
  • @AndrewSteitz:的确,只写一个返回Person的Clone()方法就好了.我觉得使用'Person clonedPerson = new Person(originalPerson);'会更好.很明显,返回类Person的新对象,而'originalPerson.Clone()'可以返回originalPerson.当然,这没有多大意义,但构造函数保证返回一个新对象. (2认同)

Kas*_*iel 14

我使用AutoMapper.它的工作原理如下:

Mapper.CreateMap(typeof(Person), typeof(Person));
Mapper.Map(a, b);
Run Code Online (Sandbox Code Playgroud)

现在,人a具有人b的所有属性.

另外,AutoMapper也适用于不同的对象.有关更多信息,请访问http://automapper.org

更新:我现在使用这个语法(简单来说 - CreateMaps真的在AutoMapper配置文件中):

Mapper.CreateMap<Person, Person>;
Mapper.Map(a, b);
Run Code Online (Sandbox Code Playgroud)

请注意,您不必执行CreateMap将相同类型的一个对象映射到另一个对象,但如果不这样做,AutoMapper将创建一个浅表副本,这意味着如果您更改一个对象,另一个对象变化也.


toc*_*lle 14

由于MemberwiseClone()方法不公开,我创建了这个简单的扩展方法,以便更容易克隆对象:

public static T Clone<T>(this T obj)
{
    var inst = obj.GetType().GetMethod("MemberwiseClone", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

    return (T)inst?.Invoke(obj, null);
}
Run Code Online (Sandbox Code Playgroud)

用法:

var clone = myObject.Clone();
Run Code Online (Sandbox Code Playgroud)


Cht*_*lek 8

要克隆类对象,可以使用Object.MemberwiseClone方法,

只需将此功能添加到您的班级:

public class yourClass
{
    // ...
    // ...

    public yourClass DeepCopy()
    {
        yourClass othercopy = (yourClass)this.MemberwiseClone();
        return othercopy;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后执行深度独立副本,只需调用DeepCopy方法:

yourClass newLine = oldLine.DeepCopy();
Run Code Online (Sandbox Code Playgroud)

  • 您可能应该将其称为"ShallowCopy",因为在大多数情况下它会导致浅拷贝.(参见https://msdn.microsoft.com/de-de/library/system.object.memberwiseclone(v=vs.110).aspx上的示例) (4认同)

小智 8

没有比这更简单的了:

    public SomeClass Clone () {

        var clonedJson = JsonConvert.SerializeObject (this);

        return JsonConvert.DeserializeObject<SomeClass> (clonedJson);
    }
Run Code Online (Sandbox Code Playgroud)

只需将任何对象序列化为 JSON 字符串,然后反序列化即可。这将进行深度复制......


Mat*_*hen 6

a并且b只是对同一Person对象的两个引用.他们都基本上持有的地址Person.

有一个ICloneable接口,虽然相对较少的类支持它.有了这个,你会写:

Person b = a.Clone();
Run Code Online (Sandbox Code Playgroud)

然后,b将完全分开Person.

您还可以实现一个复制构造函数:

public Person(Person src)
{
  // ... 
}
Run Code Online (Sandbox Code Playgroud)

没有内置方法可以复制所有字段.你可以通过反射来实现,但会有性能损失.

  • 不要使用IClonable:http://blogs.msdn.com/b/brada/archive/2003/04/09/49935.aspx (3认同)