C# 如何创建列表集合的深度副本

C# 如何创建列表集合的深度副本,c#,deep-copy,shallow-copy,C#,Deep Copy,Shallow Copy,假设我有以下课程: public class Author { public int ID {get; private set;} public string firstName {get; private set;} public string lastName {get; private set; } public Author(int id, string firstname, string lastname) { this.ID

假设我有以下课程:

public class Author
{
    public int ID {get; private set;}
    public string firstName {get; private set;}
    public string lastName {get; private set; }

    public Author(int id, string firstname, string lastname)
    {
        this.ID = ID;
        this.firstName = firstname;
        this.lastName = lastName;
    }

    public static Author Clone(Author clone)
    {
        Author copyAuth = new Author(clone.ID, clone.firstName, clone.lastName);
        return copyAuth;
    }
}

公共课堂教材
{
公共字符串bookTitle{get;private set;}
创建我的克隆方法的私有列表

问题1:

    public List<Author> Authors
    {
        get
        {
            return returnAuthors(authors);
        }

    }

    private List<Author> returnAuthors(List<Author> copyList)
    {
        List<Author> getAuthors = new List<Author>();

        foreach(Author copy in copyList){
            getAuthors.Add(Author.Clone(copy));
        }

        return getAuthors;
    }
上面的实现被认为是深度复制吗?如果是,这样做可以吗?我的意思是,构造函数中的foreach循环将作者复制到一个新的列表集合

问题2:

    public List<Author> Authors
    {
        get
        {
            return returnAuthors(authors);
        }

    }

    private List<Author> returnAuthors(List<Author> copyList)
    {
        List<Author> getAuthors = new List<Author>();

        foreach(Author copy in copyList){
            getAuthors.Add(Author.Clone(copy));
        }

        return getAuthors;
    }
如果我修改copyofAuthor集合中的任何内容,它将不再引用原始集合,对吗?因此原始集合应保持不变

更新#1:

    public List<Author> Authors
    {
        get
        {
            return returnAuthors(authors);
        }

    }

    private List<Author> returnAuthors(List<Author> copyList)
    {
        List<Author> getAuthors = new List<Author>();

        foreach(Author copy in copyList){
            getAuthors.Add(Author.Clone(copy));
        }

        return getAuthors;
    }
公开列表作者
{
得到
{
返回返回作者(作者);
}
}
私人列表返回作者(列表复制列表)
{
List getAuthors=newlist();
foreach(版权列表中的作者副本){
getAuthors.Add(Author.Clone(copy));
}
返回getAuthors;
}
我是否正确地实现了getter集合,当它返回列表集合时,它独立于原始集合?因此从getter返回的集合所做的任何更改都不会反映在原始集合中

更新#2:

    public List<Author> Authors
    {
        get
        {
            return returnAuthors(authors);
        }

    }

    private List<Author> returnAuthors(List<Author> copyList)
    {
        List<Author> getAuthors = new List<Author>();

        foreach(Author copy in copyList){
            getAuthors.Add(Author.Clone(copy));
        }

        return getAuthors;
    }
具有只读集合

    public class Book
    {

        public string bookTitle {get; private set;}
        private ReadOnlyCollection<Author> authors;
        public string ISBN {get; private set; }


        public Book(string bookTitle, ReadOnlyCollection<Author> authors, string ISBN)
        {

            this.bookTitle = bookTitle;
            this.ISBN = ISBN;
            //Is it okay to do this? 
            this.authors = authors;

        }

        public List<Author> Authors
        {
            get
            {   //Create a shallow copy
                return new ReadOnlyCollection<Author>(authors);
            }

        }

    }
公共课堂教材
{
公共字符串bookTitle{get;private set;}
私人只读集合作者;
公共字符串ISBN{get;private set;}
公共图书(字符串书名、只读集合作者、字符串ISBN)
{
this.bookTitle=bookTitle;
这是ISBN=ISBN;
//这样可以吗?
this.authors=作者;
}
公开名单作者
{
得到
{//创建一个浅拷贝
返回新的只读集合(作者);
}
}
}

如果您有许多属性,那么编写以下内容会很无聊:

new Author(clone.ID, clone.firstName, clone.lastName...);
查看这个小示例,了解如何实现
ICloneable
接口:

这个例子来自:

问题1: 是的,这将执行深度复制。我建议使用IClonable interface,而不是此静态函数,因为它是标准的

问题2: 是,在使用新集合对象时,原始集合不会更改

问题3: 如果您在getter中返回集合,则有人可以对其进行转换。您可以在每次有人想要获取集合时返回该集合的新副本,或者将其包装在一个容器中,该容器将具有私有只读集合,并且不会公开该集合(但可以是可枚举的)


在您的情况下,不确定您是否希望作者是独立的。鉴于他们已经只能私下设置,共享他们的更新可能会很有用。唯一需要保持独立的是集合。因此可能不需要克隆作者。

在评论中对其进行分类太难了

  • 从Author类中删除Clone方法。它是无用的
在你的书本课上,你有两个问题要解决

  • 构造函数获取作者列表,但传入该列表的调用方可能会对其进行更改。如果我们只是复制引用,则调用方可能会意外地更改书本中的列表

  • 这本书会返回一个作者列表。如果来电者在列表中添加了一些内容,那么他们就改变了这本书

使用不可变集合可以解决这两个问题。如果尚未获得不可变集合库,请使用NuGet下载该库

using System.Collections.Immutable;
...
public class Book
{
  public string bookTitle {get; private set;}
  private ImmutableList<Author> authors;
  public IReadOnlyList<Author> Authors { get { return authors; } }
  public string ISBN {get; private set; }

  public Book(string bookTitle, IEnumerable<Author> authors, string ISBN)
  {
    this.authors = ImmutableList<Author>.Empty.AddRange(authors);
    this.bookTitle = bookTitle;
    this.ISBN = ISBN;
  }
}

等等。

我发布的链接说ICloneable应该贬值,而不是使用它。你能告诉我如何实现复制集合的getter吗?我可以像在构造函数中一样使用一个循环的私有方法吗?如果我更新我的问题,你能看一下并给出建议吗?我通常使用
Activator.CreateInstance来具体化深度克隆的对象。当然,它使用反射,但对我的用例来说,性能影响可以忽略不计(通常希望克隆一个相当“浅”的数组)代码表现力方面的好处超过了缺点。在您的情况下,静态克隆方法可能满足您的目的。您是否在寻找对您的技术的验证?如果是,静态
Author.clone()没有什么特别的问题
方法。与iClonable相比,这种方法的好处在于,你可以得到一个真正的
作者,而不是
对象。
你能描述一下让你相信深度复制是一个好主意的场景吗?它在时间和内存上都很昂贵,而且很难正确获得。你最好使用一个持久不变的col如果您想对原始列表进行多个独立编辑,请选择。特别是考虑到作者已经是不可变的;为什么您首先要克隆一个?@K.AlanBates-非常感谢,我正在寻找此方法的验证,您能检查我的更新并提出建议吗?我实现了一个getter,想知道是否我做得很好。从阅读文档开始。如果你正在编写代码,而你不知道为什么要编写代码,那么你今天就开始编写代码太早了。在你知道为什么要编写代码之后再编写代码。不要担心深拷贝和浅拷贝;这是一个很少重要的区别。想想应该进行哪些操作您的方法的使用者能够执行。您考虑这些使用者是否可以改变您的集合是绝对正确的!如果这是您的问题,那么不要让他们改变您的集合。将一个不可变的集合交给他们。非常感谢!这只是为了我的理解。当您实现克隆方法时,只为muta这样做ble obj
public class Book
{
  public string Title {get; private set;}
  private ImmutableList<Author> authors;
  public IReadOnlyList<Author> Authors { get { return authors; } }
  public string ISBN {get; private set; }

  public Book(string title, IEnumerable<Author> authors, string ISBN) : this(
    title, 
    ImmutableList<Author>.Empty.AddRange(authors),
    ISBN) {}

  public Book(string title, ImmutableList<Authors> authors, string ISBN) 
  {
    this.Title = title;
    this.Authors = authors;
    this.ISBN = ISBN;
  }
  public Book WithTitle(string newTitle)
  {
    return new Book(newTitle, authors, ISBN); 
  }
  public Book WithISBN(string newISBN)
  {
    return new Book(Title, authors, newISBN);
  }
  public Book WithAuthor(Author author)
  {
    return new Book(Title, authors.Add(author), ISBN);
  }
  public static readonly Empty = new Book("", ImmutableList<Author>.Empty, "");
}
Book tlotr = Book.Empty.WithAuthor("JRRT").WithTitle("The Lord Of The Rings");