不使用 serialize/deserialize 的深层复制

deep copy without using serialize/deserialize

如何在不执行 serialize/deserialize 的情况下深度复制 class 对象?

例如

public class Book
{
    public string Chapter { get; set;}
    public int Page { get; set;}
}

public void Main ()
{
   Book newBook = new Book();
   newBook.Chapter = "Physical";
   newBook.Page = 40;

   Book oldBook = newBook; 
   
   newBook.Chapter = "Chemical";
   newBook.Page = 60;
   
}

------------------------------
output
newBook.Chapter: Chemical
newBook.Page: 60

oldBook.Chapter: Chemical
oldBook.Page: 60

但我想要这个

newBook.Chapter:化学品
newBook.Page: 60

oldBook.Chapter:物理
oldBook.Page: 40

当对象具有足够多的属性以至于编写自定义代码会很耗时时,序列化和反序列化很流行,但您可以只写:

public static class BookExtensions
{
    public static Book Clone(this Book source)
    {
        return new Book {Chapter = source.Chapter, Page = source.Page};
    }
}

或者使之成为Book的方法。是执行此操作还是创建扩展(如上)是一个偏好问题。如果该方法在 Book 中,那么您更有可能记得在 class 发生变化时更新该方法。

public class Book
{
    public string Chapter { get; set; }
    public int Page { get; set; }

    public Book Clone()
    {
        return new Book {Chapter = Chapter, Page = Page};
    }
}

(有一个ICloneable接口你可以实现,但它不流行。Clone方法returns object你必须转换它。)

另一种方法是使用 structrecord。您可能正在克隆,以便您可以拥有与另一个实例相同的实例,但您可以修改其属性而不更改第一个实例。

如果您将 Book class 更改为 struct,则此测试通过:

var book = new Book {Chapter = "x", Page = 1};
var book2 = book;
book2.Page = 2;
Assert.AreEqual(1, book.Page);

不需要克隆任何东西。

或者您可以创建 record:

public record class Book(string chapter, int page)
{ }

并且此测试通过:

var book = new Book("x", 1);
var book2 = book with {page = 2};
Assert.AreEqual(1, book.page);

每个 Book 都是不可变的。您可以将它传递给各种方法,每当 属性 需要“更改”时,像 var book2 = book with {page = 2}; 这样的语句会创建一本新书,并且只更新指定的 属性。无需克隆。