假设我有以下类(class):
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;
}
}
和
public class Book
{
public string bookTitle {get; private set;}
private List<Author> authors;
private List<Author> copyofAuthors;
public string ISBN {get; private set; }
public Book(string bookTitle, List<Author> authors, string ISBN)
{
copyofAuthors = new List<Author>();
this.bookTitle = bookTitle;
this.ISBN = ISBN;
//How do I create a deep copy of my authors List?
foreach(Author copy in authors)
{
Author addAuthors = Author.Clone(copy);
copyofAuthors.Add(addAuthors);
}
}
}
我将如何创建我的 List<Authors>
的深拷贝收藏?我已经阅读了 StackOverFlow 上建议序列化的其他页面,以及我不熟悉且看起来令人困惑的建议。
我关注了this link创建我的克隆方法。
问题 1:
上面的实现是否被认为是深拷贝?如果是这样,这样做可以吗?我的意思是,构造函数中的 foreach 循环将作者复制到新的列表集合。
问题 2:
如果我修改了 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;
}
我是否正确地实现了我的 getter 集合,以便当它返回 List 集合时,它独立于原始集合?因此,对从 getter 返回的集合所做的任何更改都不会反射(reflect)在原始集合中,对吗?
更新#2:
使用 ReadOnlyCollection
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);
}
}
}
最佳答案
很难在评论中解决这个问题。
- 从您的 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;
}
}
那里。现在您制作了作者序列的副本,因此如果调用者更改了该序列,不用担心,您有一个副本。然后你分发一个由不可变集合实现的 IReadOnlyList,因此没有人可以更改它。
结合更多的东西。你问“这样对吗?”
public class Book
{
private ReadOnlyCollection<Author> authors;
public Book(ReadOnlyCollection<Author> authors)
{
//Is it okay to do this?
this.authors = authors;
}
public List<Author> Authors
{
get
{ //Create a shallow copy
return new ReadOnlyCollection<Author>(authors);
}
}
(已删除无关内容)。
不,出于几个原因,这不太正确。首先,只读集合只是可变集合的包装器。您仍然处于调用者控制基础集合的情况,因此可以更改它。
其次,打字不太好;您不能将 ReadOnlyCollection 转换为列表。
我知道这很令人困惑。这里有一个微妙的区别。只读集合就是:您只能阅读它。这并不意味着其他人 不能写它!这样的集合仍然可变,只是您不可改变。不可变集合是真正不可变的;没有人可以改变它。
下一步:通过使作者和书籍都保持不变,您做得很好。但是如果你想改变它怎么办?正如您所注意到的,改变一本不变的书意味着制作一本新书。但是你已经有了一本旧书;你怎么能有效地做到这一点?常见的模式是:
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");
等等。
关于c# - 如何创建我的列表集合的深拷贝,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35847307/