2012-11-06 76 views
3

當我在lstCopy中創建原始列表lstStudent的副本並將lstCopy發送到修改函數時,lstStudent也會被修改。我想保持這個列表不被修改。如何在修改副本時保持通用列表不被修改?

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"; 
     } 
    } 
} 
+0

向我們展示什麼'Logic.ModifyList'一樣。 –

+1

可能的重複 - http://stackoverflow.com/questions/222598/how-do-i-clone-a-generic-list-in-c 您需要深入複製您的對象。 –

+3

你想「深入」複製列表。否則,兩個列表中的引用都指向相同的學生對象。見http://stackoverflow.com/questions/4226747/deep-copy-of-listt – MaximR

回答

0

如果您Student類型是類(引用類型),列表中只包含那些實例的引用。這意味着,當您複製清單時,複製的清單也將只有引用仍然指向相同的Student實例。通過複製你的列表,你可以簡單地複製你的引用,但不是實例。你有副本後什麼是這樣的:

List 1   List 2      instance S1 
ref to S1   ref to S1     Name: Akash 
ref to S2   ref to S2     ... 
...    ... 

所以,如果你這樣做list1[0].Name = "Jim",你會更新實例S1,你會看到兩個列表中的改變,因爲兩個列表請參考同一組實例。

你需要做的就是在這種情況下,不僅產生了列表的克隆,但所有的對象列表 - 你需要複製所有Student對象爲好。這被稱爲深層複製。事情是這樣的:

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

你叫這像這樣:

StudentList oClonedList = lstStudent.Clone() as StudentList; 

你也需要讓你的Student類可被複制通過實現ICloneable接口。不過請記住,在此之後,您將有2個獨立的列表和2個獨立的Student對象 - 修改一個Student實例將不會影響您的其他列表中的學生。

+0

公共靜態無效ModifyList(列表 lstIntegers) { 的foreach(學生S IN lstIntegers) { 如果(s.ID.Equals( 「1」)) { s.ID = 「4」; s.Name =「APS」; } } } – user1801934

+0

雅雅如何處理它? – user1801934

+0

@ user1801934對不起,不早答覆 - 我更新了我的答案。 – xxbbcc

3

您還可以通過使用二進制格式實現這一點沒有可複製的接口: 注意:所有類作爲對象圖的一部分,必須標記爲Serializable。

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

OUTPUT:

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

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

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

代碼格式化傾倒入LINQPad

編輯: 這是在這是不可能實現ICloneable情況的選項。適用時,編碼到接口。換句話說,您可以在學生對象上實現ICloneable,並使用Clone()方法中的BinaryFormatter邏輯;但是,作爲開發人員,您可以選擇自行決定要執行的操作。選項不一定是建議,建議也不總是一種選擇。有時你必須完成一項任務才能完成任務,而這正是選擇起作用的地方。

這是一個非常廣泛接受,深克隆方法: How do you do a deep copy of an object in .NET (C# specifically)?

+0

如果OP需要列表的克隆,那麼ICloneable就是應該實現的接口。當行爲與「ICloneable」完全相同時,避免使用此接口的意義何在? – xxbbcc

+1

我的解決方案提供了相同的結果。 OP需要一個克隆,ICloneable提供了現在的binaryformatter選項。這是否違反了要求?生活是關於選擇。當我沒有源代碼時,我不得不做出這樣的決定。 – Hardrada

+0

好吧,我想它可以在'Clone()'實現中使用。儘管避免使用ICloneable並不是個好建議。這個接口表示一個特定的行爲並且僅僅通過其存在來記錄代碼。我要回答-1,但如果你用ICloneable更新你的答案,並且修改格式以便正確閱讀,我將刪除它。 – xxbbcc

1

又一個快速的方法使用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); 

複製您的列表,但最好的辦法還是可以實現ICloneable深複製你的對象

0

你想要一個列表的深層副本。現在,它是一個淺拷貝。你只有兩個引用到同一個變量。沒有簡單的方法可以像使用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; 
} 

您將需要包括這些命名空間以及:

using System.IO; 
using System.Runtime.Serialization; 
using System.Runtime.Serialization.Formatters.Binary; 

然後,您可以調用該函數是這樣的:

lstCopy = getDeepCopy<List<Student>>(lstStudents);