如何克隆对象

发布于 2024-10-24 05:04:45 字数 518 浏览 1 评论 0原文

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

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;

When I do the following.. anything done to Person b modifies Person a (I thought doing this would clone Person b from Person a). I also have NO idea if changing Person a will change Person b after the linking. Due to my code right now, I can only see this in 1 direction.

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

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

Now if I do this instead.. Person a becomes completely separate.

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

Now this fine and kinda makes sense when comparing this behaviour to other things in C#. BUT, this could get very annoying with large objects.

Is there a way to shortcut this at all?

Such as:

Person b = a.Values;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

泪痕残 2024-10-31 05:04:45

您正在寻找的是克隆。您需要实现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();  

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

What you are looking is for a Cloning. You will need to Implement IClonable and then do the Cloning.

Example:

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

    #region ICloneable Members

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

    #endregion
}

Then You can simply call the Clone method to do a ShallowCopy (In this particular Case also a DeepCopy)

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

You can use the MemberwiseClone method of the Object class to do the cloning.

旧情勿念 2024-10-31 05:04:45

有没有办法缩短这个过程?

不,不是真的。您需要创建一个新实例,以避免原始实例影响“副本”。有几个选项可以实现此目的:

  1. 如果您的类型是 struct,而不是 class,它将按值复制(而不是仅复制引用)到实例)。这将为它提供您所描述的语义,但会产生许多其他副作用,这些副作用往往不太理想,并且不建议用于任何可变类型(这显然是,否则这不会成为问题!)< /p>

  2. < p>对您的类型实施“克隆”机制。这可以是ICloneable,甚至只是一个获取实例并从中复制值的构造函数。

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

Is there a way to shortcut this at all?

No, not really. You'll need to make a new instance in order to avoid the original from affecting the "copy". There are a couple of options for this:

  1. If your type is a struct, not a class, it will be copied by value (instead of just copying the reference to the instance). This will give it the semantics you're describing, but has many other side effects that tend to be less than desirable, and is not recommended for any mutable type (which this obviously is, or this wouldn't be an issue!)

  2. Implement a "cloning" mechanism on your types. This can be ICloneable or even just a constructor that takes an instance and copies values from it.

  3. Use reflection, MemberwiseClone, or similar to copy all values across, so you don't have to write the code to do this. This has potential problems, especially if you have fields containing non-simple types.

追风人 2024-10-31 05:04:45

我为此使用 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 将创建一个浅表副本,这对于外行来说意味着,如果你改变一个对象,另一个对象也会改变。

I use AutoMapper for this. It works like this:

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

Now person a has all the properties of person b.

As an aside, AutoMapper works for differing objects as well. For more information, check it out at http://automapper.org

Update: I use this syntax now (simplistically - really the CreateMaps are in AutoMapper profiles):

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

Note that you don't have to do a CreateMap to map one object of the same type to another, but if you don't, AutoMapper will create a shallow copy, meaning to the lay man that if you change one object, the other changes also.

倾城月光淡如水﹏ 2024-10-31 05:04:45

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

Since the MemberwiseClone() method is not public, I created this simple extension method in order to make it easier to clone objects:

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

Usage:

var clone = myObject.Clone();
娜些时光,永不杰束 2024-10-31 05:04:45

它再简单不过了:

    public SomeClass Clone () {

        var clonedJson = JsonConvert.SerializeObject (this);

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

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

It couldn't be simpler than this:

    public SomeClass Clone () {

        var clonedJson = JsonConvert.SerializeObject (this);

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

Just serialize any object to a JSON string and then deserialize it. This will do a deep copy...

被你宠の有点坏 2024-10-31 05:04:45

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

只需将此函数添加到您的类中:

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

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

然后要执行深度独立复制,只需调用 DeepCopy 方法:

yourClass newLine = oldLine.DeepCopy();

To clone your class object you can use the Object.MemberwiseClone method,

just add this function to your class :

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

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

then to perform a deep independent copy, just call the DeepCopy method:

yourClass newLine = oldLine.DeepCopy();
妖妓 2024-10-31 05:04:45

ab 只是对同一 Person 对象的两个引用。它们本质上都保存着Person的地址。

有一个 ICloneable 接口,尽管支持它的类相对较少。这样,您可以这样写:

Person b = a.Clone();

那么,b 将是一个完全独立的 Person

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

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

没有内置方法可以复制所有字段。您可以通过反射来做到这一点,但会降低性能。

a and b are just two references to the same Person object. They both essentially hold the address of the Person.

There is a ICloneable interface, though relatively few classes support it. With this, you would write:

Person b = a.Clone();

Then, b would be an entirely separate Person.

You could also implement a copy constructor:

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

There is no built-in way to copy all the fields. You can do it through reflection, but there would be a performance penalty.

流绪微梦 2024-10-31 05:04:45

你可以这样做:

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

对于深度克隆,你可能想看看这个答案:
https://stackoverflow.com/a/78612/550975

You could do it like this:

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

For deep cloning you may want to take a look at this answer:
https://stackoverflow.com/a/78612/550975

夕嗳→ 2024-10-31 05:04:45

正如其他人所建议的那样,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();

MemberwiseClone is a good way to do a shallow copy as others have suggested. It is protected however, so if you want to use it without changing the class, you have to access it via reflection. Reflection however is slow. So if you are planning to clone a lot of objects it might be worthwhile to cache the result:

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

You can call it like this:

Person b = a.ShallowClone();
戏蝶舞 2024-10-31 05:04:45

无痛:使用 NClone

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

Painlessly: Using NClone library

Person a = new Person() { head = "big", feet = "small" };
Person b = Clone.ObjectGraph(a); 
半﹌身腐败 2024-10-31 05:04:45
  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;
  }
  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;
  }
中性美 2024-10-31 05:04:45

与 @ChtiouiMalek 的答案类似,但使用 System.Text.Json 您可以序列化和反序列化以获得对象的深层克隆,例如

    string json = JsonSerializer.Serialize<Person>(person);
    Person personClone = JsonSerializer.Deserialize<Person>(json);

,当然,您可以将其作为 1-liner 来执行:

    Person personClone = JsonSerializer.Deserialize<Person>(
        JsonSerializer.Serialize<Person>(person));

Similar to @ChtiouiMalek's answer but with System.Text.Json you can serialize and deserialize to get a deep clone of your object, e.g.

    string json = JsonSerializer.Serialize<Person>(person);
    Person personClone = JsonSerializer.Deserialize<Person>(json);

And, of course, you can do it as a 1-liner:

    Person personClone = JsonSerializer.Deserialize<Person>(
        JsonSerializer.Serialize<Person>(person));
稀香 2024-10-31 05:04:45

在我看来,最好的方法是实现您自己的 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,因为它不是引用,而是克隆。

希望我能帮忙!

In my opinion, the best way to do this is by implementing your own Clone() method as shown below.

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(
quot;{a.head}, {a.feet}");
        Console.WriteLine(
quot;{b.head}, {b.feet}");
    }
}

Output:

bigAf, smol

notEvenThatBigTBH, smol

b is totally independent to a, due to it not being a reference, but a clone.

Hope I could help!

泪之魂 2024-10-31 05:04:45

这段代码对我有用。它还需要很少的时间来执行。

    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;
            }
        };
    }

This code worked for me. It also takes a very small amount of time to execute.

    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;
            }
        };
    }
不即不离 2024-10-31 05:04:45
private static readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true
};
public static T? FromJson<T>(this string json) => JsonSerializer.Deserialize<T>(json, _jsonOptions);
public static string ToJson<T>(this T obj) where T : class => JsonSerializer.Serialize(obj, _jsonOptions);
public static T? Clone<T>(this T obj) where T : class => obj.ToJson().FromJson<T>();

这就是我使用内置 Json 类解决它并创建一些扩展方法的方法。这些扩展方法在我的整个项目中都很有用。 (这是在 .NET 6 上运行的)

private static readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true
};
public static T? FromJson<T>(this string json) => JsonSerializer.Deserialize<T>(json, _jsonOptions);
public static string ToJson<T>(this T obj) where T : class => JsonSerializer.Serialize(obj, _jsonOptions);
public static T? Clone<T>(this T obj) where T : class => obj.ToJson().FromJson<T>();

This is how I have solved it using the built in Json class and created some extension methods. These extension methods come in handy all over my project. (This is running on .NET 6)

£冰雨忧蓝° 2024-10-31 05:04:45

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

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

只需将 Person 声明从 更改

class Person

struct Person

This happens because "Person" is a class, so it is passed by reference.
In the statement "b = a" you are just copying a reference to the one and only "Person" instance that you created with the keyword new.

The easiest way to have the behavior that you are looking for is to use a "value type".

Just change the Person declaration from

class Person

to

struct Person
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文