如何创建List<;T>;

本文关键字:lt gt List 何创建 创建 | 更新日期: 2023-09-27 17:49:23

在下面的代码中,

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace clone_test_01
{
    public partial class MainForm : Form
    {
        public class Book
        {
            public string title = "";
            public Book(string title)
            {
                this.title = title;
            }
        }

        public MainForm()
        {
            InitializeComponent();
            List<Book> books_1 = new List<Book>();
            books_1.Add(  new Book("One")  );
            books_1.Add(  new Book("Two")  );
            books_1.Add(  new Book("Three")  );
            books_1.Add(  new Book("Four")  );
            List<Book> books_2 = new List<Book>(books_1);
            books_2[0].title = "Five";
            books_2[1].title = "Six";
            textBox1.Text = books_1[0].title;
            textBox2.Text = books_1[1].title;
        }
    }
}

我使用Book对象类型来创建List<T>,并用几个项目填充它,给它们一个唯一的标题(从"一"到"五"(。

然后我创建了List<Book> books_2 = new List<Book>(books_1)

从这一点来看,我知道它是列表对象的克隆,但book_2中的图书对象仍然是books_1中图书对象的引用。通过对books_2的前两个元素进行更改,然后在TextBox中检查book_1的相同元素,可以证明这一点。

CCD_ 9实际上已经被改变为CCD_。

现在的问题

我们如何创建List<T>的新硬拷贝?其思想是CCD_ 12和CCD_。

我感到失望的是,微软没有提供像Ruby使用clone()方法那样简洁、快速、简单的解决方案。

助手真正棒的地方是使用我的代码,并用一个可行的解决方案修改它,这样它就可以编译并工作了。我认为这将真正帮助新手理解为这个问题提供的解决方案。

EDIT:请注意,Book类可能更复杂,并且具有更多属性。我尽量保持简单。

如何创建List<;T>;

您需要创建新的Book对象,然后将它们放入新的List:

List<Book> books_2 = books_1.Select(book => new Book(book.title)).ToList();

更新:稍微简单一点。。。List<T>有一个名为ConvertAll的方法,它返回一个新列表:

List<Book> books_2 = books_1.ConvertAll(book => new Book(book.title));

创建一个在Book类中实现的通用ICloneable<T>接口,以便该类知道如何创建自己的副本。

public interface ICloneable<T>
{
    T Clone();
}
public class Book : ICloneable<Book>
{
    public Book Clone()
    {
        return new Book { /* set properties */ };
    }
}

然后,您可以使用Mark提到的linq或ConvertAll方法。

List<Book> books_2 = books_1.Select(book => book.Clone()).ToList();

List<Book> books_2 = books_1.ConvertAll(book => book.Clone());

我很失望微软没有提供像Ruby使用clone()方法那样简洁、快速、简单的解决方案。

除了不会创建深度副本之外,它会创建浅层副本。

对于深度复制,你必须始终小心,你到底想复制什么。一些可能问题的例子有:

  1. 在对象图中循环。例如,Book具有Author,而Author具有他的Book的列表
  2. 对某个外部对象的引用。例如,一个对象可能包含向文件写入的打开的Stream
  3. 事件。如果一个对象包含一个事件,那么几乎任何人都可以订阅它。如果订阅者类似于GUI Window,这可能会特别有问题

现在,基本上有两种方法可以克隆:

  1. 在需要克隆的每个类中实现一个Clone()方法。(还有ICloneable接口,但您应该不要使用它;按照Trevor的建议使用自定义ICloneable<T>接口是可以的。(如果您知道您只需要创建这个类的每个字段的浅副本,那么您可以使用MemberwiseClone()来实现它。作为替代方案,您可以创建一个"复制构造函数":public Book(Book original)
  2. 使用序列化将对象序列化为MemoryStream,然后反序列化它们。这需要将每个类标记为[Serializable],还可以配置应该序列化的内容(以及如何序列化(。但这更像是一个"快速而肮脏"的解决方案,而且很可能性能较差

您可以使用此:

var newList= JsonConvert.DeserializeObject<List<Book>>(list.toJson());

好吧,

如果将所有涉及的类标记为可序列化,则可以:

public static List<T> CloneList<T>(List<T> oldList)  
{  
BinaryFormatter formatter = new BinaryFormatter();  
MemoryStream stream = new MemoryStream();  
formatter.Serialize(stream, oldList);  
stream.Position = 0;  
return (List<T>)formatter.Deserialize(stream);      
} 

来源:

https://social.msdn.microsoft.com/Forums/en-US/5c9b4c31-850d-41c4-8ea3-fae734b348c4/copy-listsomeobject-to-clone-list?forum=csharpgeneral

C#9记录和表达式可以让它变得更容易,尤其是当您的类型有很多属性时。

你可以使用类似的东西:

var books2 = books1.Select(b => b with { }).ToList();

我这样做是作为示例

record Book
{
    public string Name { get; set; }
}
static void Main()
{
    List<Book> books1 = new List<Book>()
    {
        new Book { Name = "Book1.1" },
        new Book { Name = "Book1.2" },
        new Book { Name = "Book1.3" }
    };
    var books2 = books1.Select(b => b with { }).ToList();
    books2[0].Name = "Changed";
    books2[1].Name = "Changed";
    Console.WriteLine("Books1 contains:");
    foreach (var item in books1)
    {
        Console.WriteLine(item);
    }
    Console.WriteLine("Books2 contains:");
    foreach (var item in books2)
    {
        Console.WriteLine(item);
    }
}

结果是:(对Books2中的对象所做的更改不会影响Books1中的原始对象(

Books1包含:

书籍{Name=Book1.1}

书籍{Name=Book1.2}

书籍{Name=Book1.3}

Books2包含:

书籍{名称=已更改}

书籍{名称=已更改}

书籍{Name=Book1.3}

List<Book> books_2 = new List<Book>(books_2.ToArray());

这应该完全符合你的意愿。在这里演示。

由于Clone将返回Book的对象实例,因此该对象首先需要转换为Book,然后才能在其上调用ToList

List<Book> books_2 = books_1.Select(book => (Book)book.Clone()).ToList();
public static class Cloner
{
    public static T Clone<T>(this T item)
    {
        FieldInfo[] fis = item.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        object tempMyClass = Activator.CreateInstance(item.GetType());
        foreach (FieldInfo fi in fis)
        {
            if (fi.FieldType.Namespace != item.GetType().Namespace)
                fi.SetValue(tempMyClass, fi.GetValue(item));
            else
            {
                object obj = fi.GetValue(item);
                if (obj != null)
                    fi.SetValue(tempMyClass, obj.Clone());
            }
        }
        return (T)tempMyClass;
    }
}

如果Array类满足您的需求,您还可以使用List.ToArray方法,该方法将元素复制到新数组中。

参考:http://msdn.microsoft.com/en-us/library/x303t819(v=vs.110(.aspx

复制任何通用列表的简单方法:

List<whatever> originalCopy=new List<whatever>();//create new list
originalCopy.AddRange(original);//perform copy of original list