C# 当一个通用列表的副本被修改时,如何保持它不被修改?

C# 当一个通用列表的副本被修改时,如何保持它不被修改?,c#,list,C#,List,当我在lstCopy中创建原始列表lststudion的副本并将lstCopy发送到修改函数时,lststudion也会被修改。我想保持这个列表不变 List<Student> lstStudent = new List<Student>(); Student s = new Student(); s.Name = "Akash"; s.ID = "1"; lstStudent.Add(s); List<Student> lstCopy = new List&

当我在lstCopy中创建原始列表lststudion的副本并将lstCopy发送到修改函数时,lststudion也会被修改。我想保持这个列表不变

List<Student> lstStudent = new List<Student>();
Student s = new Student();
s.Name = "Akash";
s.ID = "1";
lstStudent.Add(s);
List<Student> lstCopy = new List<Student>(lstStudent);
Logic.ModifyList(lstCopy);
// "Want to use lstStudent(original list) for rest part of the code"

public static void ModifyList(List<Student> lstIntegers) { 
    foreach (Student s in lstIntegers) { 
        if (s.ID.Equals("1")) { 
            s.ID = "4"; s.Name = "APS"; 
        } 
    } 
}
List lststudion=newlist();
学生s=新学生();
s、 Name=“Akash”;
s、 ID=“1”;
1.添加(s);
List lstCopy=新列表(学生列表);
逻辑修改列表(lstCopy);
//“要将LSTStuent(原始列表)用于代码的其余部分”
公共静态void ModifyList(列表整数){
foreach(学生的整数){
如果(s.ID.Equals(“1”){
s、 ID=“4”s.Name=“APS”;
} 
} 
}

如果您的
学生
类型是类(参考类型),则列表将仅包含对这些实例的引用。这意味着,当您复制列表时,复制的列表也将只有仍然指向相同的
学生
实例的引用。通过复制列表,您只需复制引用,而不复制实例。复印件后的内容如下:

List 1            List 2                     instance S1
ref to S1         ref to S1                  Name: Akash
ref to S2         ref to S2                  ...
...               ...
class StudentList : List<Student>, ICloneable
{
    public object Clone ()
    {
        StudentList oNewList = new StudentList ();

        for ( int i = 0; i < Count; i++ )
        {
            oNewList.Add ( this[i].Clone () as Student );
        }

        return ( oNewList );
    }
}
lstCopy = getDeepCopy<List<Student>>(lstStudents);
因此,如果您执行类似于
list1[0].Name=“Jim”
的操作,您将更新实例
S1
,您将在两个列表中看到更改,因为两个列表都引用同一组实例

在本例中,您需要做的不仅是创建列表的克隆,而且还要创建列表中所有对象的克隆-您还需要克隆所有
学生
对象。这称为深度复制。大概是这样的:

List 1            List 2                     instance S1
ref to S1         ref to S1                  Name: Akash
ref to S2         ref to S2                  ...
...               ...
class StudentList : List<Student>, ICloneable
{
    public object Clone ()
    {
        StudentList oNewList = new StudentList ();

        for ( int i = 0; i < Count; i++ )
        {
            oNewList.Add ( this[i].Clone () as Student );
        }

        return ( oNewList );
    }
}
lstCopy = getDeepCopy<List<Student>>(lstStudents);
您还需要通过实现接口使您的
学生
类可克隆


不过,不要忘记,在此之后,您将有两个单独的列表,其中包含两组独立的
Student
对象-修改一个
Student
实例将不会对其他列表中的学生产生任何影响。

我将查看iClonable。你要的是“深度复制”。这篇文章中有很多好的信息:


您也可以通过使用二进制格式化程序在没有可克隆接口的情况下实现这一点: 注意:作为对象图一部分的所有类都必须标记为可序列化

void Main()
{
   var student1=new Student{Name="Bob"};
   var student2=new Student{Name="Jim"};

   var lstStudent=new List<Student>();
   lstStudent.Add(student1);
   lstStudent.Add(student2);

   var lstCopy=new List<Student>(lstStudent);
   var clone=Clone(lstStudent);

   student1.Name="JOE";

   lstCopy.Dump();
   lstStudent.Dump();
   clone.Dump();

}

public List<Student> Clone(List<Student> source)
{

   BinaryFormatter bf=new BinaryFormatter();
   using(var ms=new MemoryStream())
   {
     bf.Serialize(ms,source);
     ms.Seek(0,0);
     return (List<Student>)bf.Deserialize(ms);
   }
}

[Serializable]
public class Student
{
  public string Name { get; set; }
}
void Main()
{
var student1=新学生{Name=“Bob”};
var student2=新学生{Name=“Jim”};
var lststuden=新列表();
lstStudent.Add(student1);
lstStudent.Add(student2);
var lstCopy=新列表(lstStudent);
var clone=clone(学生);
学生1.Name=“乔”;
lstCopy.Dump();
lststuden.Dump();
clone.Dump();
}
公共列表克隆(列表源)
{
BinaryFormatter bf=新的BinaryFormatter();
使用(var ms=new MemoryStream())
{
bf.序列化(ms,来源);
Seek女士(0,0);
返回(列表)bf.反序列化(ms);
}
}
[可序列化]
公立班学生
{
公共字符串名称{get;set;}
}
输出:

5List<Student> (2 items) 4  
Name 
JOE 
Jim 

5List<Student> (2 items) 4  
Name 
JOE 
Jim 

5List<Student> (2 items) 4  
Name 
Bob 
Jim 
5列表(2项)4
名称
乔
吉姆
5清单(2项)4
名称
乔
吉姆
5清单(2项)4
名称
上下快速移动
吉姆
代码已格式化,以便转储到LINQPad中

编辑: 在无法实现
ICloneable
的情况下,这是一个选项。适用时,将代码添加到接口。换句话说,您可以在student对象上实现
ICloneable
,并在
Clone()
方法中使用
BinaryFormatter
逻辑;但是,作为一名开发人员,您可以选择自己决定要做什么。选择不一定是建议,建议也不总是一种选择。有时,你必须尽全力完成一项任务,而这正是选择发挥作用的地方

这是一种被广泛接受的深度克隆方法:

这是使用LINQ复制列表的另一种快捷方式

List<student> oldList = new List<student> { new student{
                                             id=122,
                                             name="John"} };

IEnumerable<student> copy= oldList.Select(item => new student{
                                             id = item.id,
                                             name = item.name });

List<student> newList= new List<student>(copy);
List oldList=new List{new student{
id=122,
name=“John”};
IEnumerable copy=旧列表。选择(项=>新学生{
id=item.id,
名称=item.name});
List newList=新列表(副本);

但是最好的选择仍然是实现IClonable来深度复制您的对象

您需要列表的深度副本。现在,这是一个肤浅的副本。同一个变量只有两个引用。在C++中,没有一种简单的方法可以像C语言那样获得深层拷贝。获取深度副本的一种方法是序列化和反序列化第一个列表。下面是一个模板化函数,用于获取对象的深度副本

public static T getDeepCopy<T>( T objectToCopy )
{
    T temp;
    using ( MemoryStream ms = new MemoryStream() )
    {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize( ms, objectToCopy );
        ms.Position = 0;
        temp = (T)formatter.Deserialize( ms );
    }
    return temp;
}
然后可以像这样调用函数:

List 1            List 2                     instance S1
ref to S1         ref to S1                  Name: Akash
ref to S2         ref to S2                  ...
...               ...
class StudentList : List<Student>, ICloneable
{
    public object Clone ()
    {
        StudentList oNewList = new StudentList ();

        for ( int i = 0; i < Count; i++ )
        {
            oNewList.Add ( this[i].Clone () as Student );
        }

        return ( oNewList );
    }
}
lstCopy = getDeepCopy<List<Student>>(lstStudents);
lstCopy=getDeepCopy(lstCopy);

向我们展示
逻辑。ModifyList
的功能。可能重复-您需要深度复制对象。您想“深度”复制列表。否则,两个列表中的引用都指向相同的学生对象。请参阅公共静态void ModifyList(List lstIntegers){foreach(Student s in lstIntegers){if(s.ID.Equals(“1”){s.ID=“4”;s.Name=“APS”;}}}}@user1801934 Is
Student
您的类(可以访问源代码)还是您无法控制?公共静态void ModifyList(List lstugers){foreach(Student s in lstugers){if(s.ID.Equals(“1”){s.ID=“4”s.Name=“APS”;}}@user1801934抱歉没有早点回复-我更新了我的答案。@xxbbcc您需要从函数返回您的列表。公共类学生:ICLONABLE{public string ID{get;set;}公共字符串名称{get;set;}公共对象克隆(){Student newPerson=(学生)this.MemberwiseClone();return newPerson;}}}如果OP需要列表的克隆,
ICloneable
正是中间层