如何创建我的名单收集的深层复制 [英] How can I create a deep copy of my list collection

查看:109
本文介绍了如何创建我的名单收集的深层复制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有下面的类:

 公共类作者
{
公众诠释ID {得到;私人集;}
公共字符串的firstName {搞定;私人集;}
公共字符串的lastName {搞定;私人集; }

公共作者(INT ID,串名字,姓氏字符串)
{
this.ID = ID;
this.firstName =名字;
this.lastName = lastName的;
}

公共静态作者克隆(作者克隆)
{
作者copyAuth =新的作者(clone.ID,clone.firstName,clone.lastName);
返回copyAuth;
}
}

 公共类图书
{
公共字符串BOOKTITLE {搞定;私人集;}
私有列表<作者>作者;
私有列表<作者> copyofAuthors;
公共字符串ISBN {搞定;私人集; }

公共图书(字符串BOOKTITLE,列表与LT;作者>作者,串ISBN)
{
copyofAuthors =新的List<作者>();
this.bookTitle = BOOKTITLE;
this.ISBN = ISBN;
//我如何创建我的作者名单的深层副本?

的foreach(在作者作者复印件)
{
作者addAuthors = Author.Clone(复印件);
copyofAuthors.Add(addAuthors);
}
}
}



我将如何创建一个深我的的副本列表<&作者GT; 收藏?我读过关于StackOverflow的其他页面的提示序列化,那我不熟悉,似乎令人困惑的建议。



我跟着的此链接创建我的clone方法



问题1:



被认为是深拷贝上面的实现?如果是这样,什么情况下可以做这种方式?我的意思是,一个foreach循环在构造复制,作者以一个新的列表集合



问2:



如果我的copyofAuthor收集修改任何东西,它的不再引用原始集合正确吗? ?所以,在原始收集应保持不变。



更新#1:



 公开名单<作者>作者
{
得到
{
返回returnAuthors(作者);
}

}

私人列表<作者> returnAuthors(列表<作者> copyList)
{
名单,LT;作者> getAuthors =新的List<作者>();

的foreach(在copyList作者复印件){
getAuthors.Add(Author.Clone(复印件));
}

返回getAuthors;
}

让我实现我的getter收集正确,这样当它返回的List集合, 这是独立于原始集合?因此,从吸气的返回从集合所做的任何更改将不会反映原集合中是否正确?



更新#2:



通过ReadOnlyCollection还



 公共类图书
{

公共字符串BOOKTITLE {搞定;私人集;}
私人ReadOnlyCollection还<作者>作者;
公共字符串ISBN {搞定;私人集; }


公共图书(字符串BOOKTITLE,ReadOnlyCollection还<作者>作者,ISBN字符串)
{

this.bookTitle = BOOKTITLE;
this.ISBN = ISBN;
//什么情况下可以做到这一点?
this.authors =作家;

}

公开名单<作者>作者
{
得到
{//创建一个浅表副本
返回新ReadOnlyCollection还<作者>(作家);
}

}

}


解决方案

它变得太硬的评论排序了这一点。




  • 删除克隆方法从你的Author类。这是没用的。



在你的书类中,有两个问题需要解决。




  • 构造函数作者的列表,但谁通过它调用者可能会改变它。如果我们只是复制引用,那么调用者可以意外地改变了图书举办的列表。


  • 这本书还给作者列表。如果主叫方然后再添加东西的清单,他们已经变异了这本书。




您可以解决这两个问题与不可变集合。下载使用的NuGet如果你还没有得到它已经不可改变的集合库

 使用System.Collections.Immutable; 
...
公共类图书
{
公共字符串BOOKTITLE {搞定;私人集;}
私人ImmutableList<作者>作者;
公共IReadOnlyList<作者>作者{{返回作者; }}
公共字符串ISBN {搞定;私人集; }

公共图书(字符串BOOKTITLE,IEnumerable的<作者>作者,串ISBN)
{
this.authors = ImmutableList<作者> .Empty.AddRange(作者);
this.bookTitle = BOOKTITLE;
this.ISBN = ISBN;
}
}

有。现在,你做出的复制的的的的作者,所以如果呼叫者会更改顺序,不用担心,你有一个副本。你伸手,由不可变集合实现的IReadOnlyList,所以没有人可以改变它。



夫妇更多的事情。你问?这是正确的

 公共类图书
{
私人ReadOnlyCollection还<作者>作者;
公共图书(ReadOnlyCollection还<作者>作者)
{
//什么情况下可以做到这一点?
this.authors =作家;
}

公开名单<作者>作者
{
得到
{//创建一个浅表副本
返回新ReadOnlyCollection还<作者>(作家);
}
}



(多余的东西去掉)。



没有,这是不完全正确,一对夫妇的原因。首先,只读集合只是一个的包装的周围可变集合。你仍然在调用者控制的底层集合,因此可以改变它的情况。



二,打字并不完全工作了;你不能一个ReadOnlyCollection还转换到一个列表。



这是困惑,我知道。这里有一个微妙的区别。一个只读集合就是:的的只能读取它。这并不意味着的他人的不能写呢!这样一个集合仍然是的可变的,它仅仅是不可变的由您的。一个不可变的集合确实是不可变的;没有人可以改变它。



下一页:你都做得非常好通过使作者和书不可变的。但是,如果你想改变什么呢?当你注意,改变一个不可改变的书意味着让一本新书。但是你已经有一个古老的书;你怎么能做到这一点有效?常见的模式是:



 公共类图书
{
公共字符串名称{搞定;私人集;}
私人ImmutableList<作者>作者;
公共IReadOnlyList<作者>作者{{返回作者; }}
公共字符串ISBN {搞定;私人集; }

公共图书(字符串名称,IEnumerable的<作者>作者,串ISBN):这个(
标题,
ImmutableList<作者> .Empty.AddRange(作者),
ISBN){}

公共图书(字符串名称,ImmutableList<&作者GT;作者,ISBN字符串)
{
this.Title =称号;
this.Authors =作家;
this.ISBN = ISBN;
}
公共图书WithTitle(字符串newTitle的)
{
返回新的书(newTitle的作者,ISBN);
}
公共图书WithISBN(字符串newISBN)
{
返回新的书(标题,作者,newISBN);
}
公共图书WithAuthor(作者作者)
{
返回新的书(标题,authors.Add(作者),ISBN);
}
公共静态只读空=新的书(,ImmutableList<作者> .Empty,);
}

现在,你可以这样做:

 图书tlotr = Book.Empty.WithAuthor(JRRT)WithTitle(以下简称指环王); 

和等。


Suppose I have the following 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;
    }
}

and

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

How would I create a deep copy of my List<Authors> collection? I've read other pages on StackOverFlow that suggest serialization, and suggestions that I'm unfamiliar with and seem confusing.

I followed this link to create my clone method.

Questions 1:

Is the above implementation considered a deep copy? If so, is it okay to do it this way? By that I mean, a foreach loop in the constructor copying the authors to a new list collection.

Question 2:

If I modify anything in the copyofAuthor collection, it no longer references the original collection correct? So the original collection should remain the same?

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

Have I implemented my getter collection properly such that when it returns the List collection, it's independent of the original collection? So any changes made from the collection returned from the getter will not be reflected in the original collection correct?

Update #2:

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

        }

    }

解决方案

It's getting too hard to sort this out in the comments.

  • Remove the Clone method from your Author class. It is useless.

In your book class, you have two problems to solve.

  • The constructor takes a list of authors, but the caller who passed it in might change it. If we just copy the reference, then the caller can alter accidentally the list held by the book.

  • The book gives back a list of authors. If a caller adds something to that list then again, they've mutated the book.

You can solve both problems with an immutable collection. Download the immutable collections library using NuGet if you haven't got it already.

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

There. Now you make a copy of the sequence of authors, so if the caller changes that sequence, no worries, you have a copy. And you hand out an IReadOnlyList that is implemented by an immutable collection, so no one can change it.

Couple more things. You ask "is this right?"

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

(Extraneous stuff removed).

No, that is not quite right, for a couple reasons. First, the read only collection is just a wrapper around a mutable collection. You are still in the situation where the caller controls the underlying collection, and therefore can change it.

Second, the typing doesn't quite work out; you can't convert a ReadOnlyCollection to a List.

This is confusing I know. There is a subtle distinction here. A read only collection is just that: you can only read it. It doesn't mean that someone else cannot write it! Such a collection is still mutable, it is just not mutable by you. An immutable collection is truly immutable; no one can change it.

Next: you are doing very well by making the author and the book both immutable. But what if you want to change it? As you note, to change an immutable book means making a new book. But you already have an old book; how can you do that efficiently? The common pattern is:

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

Now you can do this:

Book tlotr = Book.Empty.WithAuthor("JRRT").WithTitle("The Lord Of The Rings");

And so on.

这篇关于如何创建我的名单收集的深层复制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆