如何克隆对象

时间:2011-03-19 01:11:17

标签: c# object

当我执行以下操作时...对人物b做的任何事情都会修改人物a(我认为这样做会从人物a克隆人物b)。我也不知道如果更改Person a将在链接后更改Person b。由于我的代码现在,我只能在一个方向看到这个。

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

b.head = "small"; //now a.head = "small" too   

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

Person b = new Person() { head = a.head, feet = a.feet };

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

有没有办法简化这个?

如:

Person b = a.Values;

14 个答案:

答案 0 :(得分:62)

您正在寻找克隆的内容。您需要实施IClonable然后进行克隆。

示例:

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

    #region ICloneable Members

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

    #endregion
}

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

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

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

答案 1 :(得分:38)

  

有没有办法简化这个?

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

  1. 如果您的类型是struct,而不是class,则会按值复制(而不是仅仅复制对实例的引用)。这将给你它描述的语义,但有许多其他副作用,往往不太理想,不建议任何可变类型(这显然是,或这不会是一个问题!)< / p>

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

  3. 使用反射,MemberwiseClone或类似方法复制所有值,因此您不必编写代码来执行此操作。这有潜在的问题,特别是如果你有包含非简单类型的字段。

答案 2 :(得分:13)

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

Mapper.CreateMap(typeof(Person), typeof(Person));
Mapper.Map(a, b);

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

另外,AutoMapper也适用于不同的对象。有关详细信息,请查看http://automapper.org

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

Mapper.CreateMap<Person, Person>;
Mapper.Map(a, b);

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

答案 3 :(得分:13)

由于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);
}

用法:

var clone = myObject.Clone();

答案 4 :(得分:7)

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

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

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

    public yourClass DeepCopy()
    {
        yourClass othercopy = (yourClass)this.MemberwiseClone();
        return othercopy;
    }
}

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

yourClass newLine = oldLine.DeepCopy();

答案 5 :(得分:6)

ab只是对同一Person对象的两个引用。它们基本上都包含Person的地址。

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

Person b = a.Clone();

然后,b将完全独立Person

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

public Person(Person src)
{
  // ... 
}

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

答案 6 :(得分:1)

  public static T Clone<T>(T obj)
  {
      DataContractSerializer dcSer = new  DataContractSerializer(obj.GetType());
      MemoryStream memoryStream = new MemoryStream();

      dcSer.WriteObject(memoryStream, obj);
      memoryStream.Position = 0;

      T newObject = (T)dcSer.ReadObject(memoryStream);
      return newObject;
  }

答案 7 :(得分:1)

无痛:使用NClone库

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

答案 8 :(得分:1)

没有比这更简单的了:

    public SomeClass Clone () {

        var clonedJson = JsonConvert.SerializeObject (this);

        return JsonConvert.DeserializeObject<SomeClass> (clonedJson);
    }

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

答案 9 :(得分:0)

你可以这样做:

var jss = new JavaScriptSerializer();
var b = jss.Deserialize<Person>(jss.Serialize(a));

对于深度克隆,您可能需要查看以下答案: https://stackoverflow.com/a/78612/550975

答案 10 :(得分:0)

MemberwiseClone是其他人建议的进行浅表复制的好方法。但是,它是受保护的,因此,如果要使用它而不更改类,则必须通过反射来访问它。但是反射很慢。因此,如果您打算克隆很多对象,则可能值得缓存结果:

public static class CloneUtil<T>
{
    private static readonly Func<T, object> clone;

    static CloneUtil()
    {
        var cloneMethod = typeof(T).GetMethod("MemberwiseClone", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
        clone = (Func<T, object>)cloneMethod.CreateDelegate(typeof(Func<T, object>));
    }

    public static T ShallowClone(T obj) => (T)clone(obj);
}

public static class CloneUtil
{
    public static T ShallowClone<T>(this T obj) => CloneUtil<T>.ShallowClone(obj);
}

您可以这样称呼它:

Person b = a.ShallowClone();

答案 11 :(得分:0)

我认为,最好的方法是实现自己的Clone()方法,如下所示。

class Person
{
    public string head;
    public string feet;

    // Downside: It has to be manually implemented for every class
    public Person Clone()
    {
        return new Person() { head = this.head, feet = this.feet };
    }
}

class Program
{
    public static void Main(string[] args)
    {
        Person a = new Person() { head = "bigAF", feet = "smol" };
        Person b = a.Clone();

        b.head = "notEvenThatBigTBH";

        Console.WriteLine($"{a.head}, {a.feet}");
        Console.WriteLine($"{b.head}, {b.feet}");
    }
}

输出:

  

bigAf,smol

     

notEvenThatBigTBH,smol

b完全独立于a,因为它不是参考,而是克隆。

希望我能帮上忙!

答案 12 :(得分:0)

这段代码对我有用。执行时间也非常短。

    public static void CopyTo(this object Source, object Destination)
    {
        foreach (var pS in Source.GetType().GetProperties())
        {
            foreach (var pT in Destination.GetType().GetProperties())
            {
                if (pT.Name != pS.Name) continue;
                (pT.GetSetMethod()).Invoke(Destination, new object[]
                { pS.GetGetMethod().Invoke( Source, null ) });
                break;
            }
        };
    }

答案 13 :(得分:-2)

这是因为“Person”是一个类,因此它通过引用传递。 在语句“b = a”中,您只是复制对使用关键字new创建的唯一“Person”实例的引用。

让您正在寻找的行为的最简单方法是使用“值类型”。

只需从

更改Person声明即可
class Person

struct Person