Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
188 views
in Technique[技术] by (71.8m points)

In C# How do I copy a list to another list in such a way that on modifying the copied list the original list is not modified

I am trying to copy a list to another list using AddRange or other ways but nothing seems to work correctly. No matter whatever way I try if, I modify the copied list it modifies the original list too. The only way it work if I copy using foreach loop.

    static void Main(string[] args)
    {
        var test = new List<Employee>{ new Employee { ID = "101", Name ="ABC1"}, new Employee{ID = "102", Name = "ABC2"}, new Employee{ ID = "103", Name = "ABC3"}};

        var tets2 = new List<Employee>(test);

        tets2[0].ID = "1-73";
        TestMethod(test.ToList());
    }

    private static void TestMethod(List<Employee> test)
    {
        var test1 = new List<Employee>(test);

        test1.AddRange(test);

        //This is the only one that work
        foreach(var item in test)
        {
            var x = new Employee { ID = item.ID, Name = item.Name };
            test1.Add(x);
        }

        test1[0].ID = "104";
    }

Is there no shorter way to do it?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It's not modifying the list - it's modifying the item in the list. You can have two or more lists - each is a List<Employee> - and if you copy the items to another list or array, the items in both lists are the same items.

var x = new Employee { ID = "xyz", Name = "Bob" };
var list = new List<Employee>();
list.Add(x);
var array = new Employee[]{x};
var y = x;
y.ID = "abc";

In this example there is one and only one instance of Employee, but four references to that one Employee.

  • x is one reference
  • list[0] is another
  • array[0]
  • y

However you refer to that one instance, including list[0].ID = "new id" it's all the same instance of Employee.

To create a copy you could do something like this - this is a verbose example, not necessarily the way you'd want to actually implement it:

var newList = new List<Employee>();
foreach(var employee in sourceList) //the list you want to copy from
{
    newList.Add(new Employee{ID=employee.ID, Name=employee.Name});
}

The items added to newList aren't the same objects in sourceList. They are new objects with the same properties.

If you foresee the need to do this frequently then you could make Employee implement ICloneable.

public class Employee : ICloneable
{
    public string ID {get;set;}
    public string Name {get;set;}
    public object Clone()
    {
        return new Employee{ID=ID, Name=Name};
    }
}

Or, because the properties are just value types, you could just do this, which copies properties from the source object into a new object.

public class Employee : ICloneable
{
    public string ID {get;set;}
    public string Name {get;set;}
    public object Clone()
    {
        return this.MemberwiseClone();
    }
}

Then to create a new list you could create an extension method:

public static class EmployeeExtensions
{
    public static List<Employee> ToClonedList(this IEnumerable<Employee> source)
    {
        return source.Select(employee => employee.Clone() as Employee).ToList();
    }
}

Then you can create a cloned list from any IEnumerable set of employees like this:

var myClonedList = oldList.ToClonedList();

(To split hairs, you don't have to implement ICloneable. You could just write a method that copies the object. ICloneable is just a convention that lets others know they can call .Clone() and create a cloned object.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...