如何正确存储列表<;T>;将对象项添加到列表的另一个实例<;T>;在不影响其单个项目值的情况下-C#
问题是: 我有这个班的如何正确存储列表<;T>;将对象项添加到列表的另一个实例<;T>;在不影响其单个项目值的情况下-C#,c#,list,class,C#,List,Class,问题是: 我有这个班的人: class Person { public int Id { get; set; } public string Name { get; set; } public string Position { get; set; } public int Age { get; set; } } 我将这个名为workersA的对象初始化为源对象: List<Person> workersA = new List<Person&
人
:
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Position { get; set; }
public int Age { get; set; }
}
我将这个名为workersA
的对象初始化为源对象:
List<Person> workersA = new List<Person>()
{
new Person { Id = 1, Name = "Emp1", Age = 27 },
new Person { Id = 2, Name = "Emp2", Age = 18 },
new Person { Id = 3, Name = "Emp3", Age = 23 },
};
在使用foreach
语句从源代码存储的workersC
上
foreach (var w in workersA.ToList())
{
workersC.Add(w);
}
现在,当我试图修改源对象的
Age
属性时。。代码如下:
foreach (var p in workersA.ToList())
{
p.Age--;
}
并使用以下代码输出所有结果:
Console.WriteLine("Wokers A:");
foreach (var p in workersA.ToList())
{
Console.WriteLine("Id: {0} Name: {1}, Age: {2}", p.Id, p.Name, p.Age);
}
Console.WriteLine();
Console.WriteLine("Wokers B:");
foreach (var p in workersB.ToList())
{
Console.WriteLine("Id: {0} Name: {1}, Age: {2}", p.Id, p.Name, p.Age);
}
Console.WriteLine();
Console.WriteLine("Wokers B:");
foreach (var p in workersB.ToList())
{
Console.WriteLine("Id: {0} Name: {1}, Age: {2}", p.Id, p.Name, p.Age);
}
这是我得到的:
Wokers A:
Id: 1 Name: Emp1, Age: 26
Id: 2 Name: Emp2, Age: 17
Id: 3 Name: Emp3, Age: 22
Wokers B:
Id: 1 Name: Emp1, Age: 26 // 27 - expectation
Id: 2 Name: Emp2, Age: 17 // 18 - expectation
Id: 3 Name: Emp3, Age: 22 // 22 - expectation
Wokers C:
Id: 1 Name: Emp1, Age: 26 // 27 - expectation
Id: 2 Name: Emp2, Age: 17 // 18 - expectation
Id: 3 Name: Emp3, Age: 22 // 22 - expectation
清楚地回答这个问题
为什么我得到了相同的输出
因为,归根结底,
workersB
和workersC
中的每个元素都将指向您最初创建的单个Person
实例。因此,它们都引用相同的实例-因此得到了相同的结果
简而言之,您得到了三个不同的列表,其中包含三个相同的Person
实例
执行此操作时:
workersB = workersA.ToList();
foreach (var w in workersA.ToList())
{
workersC.Add(w);
}
您可以创建列表的新实例,而不是列表中单个对象的新实例。同样,当您这样做时:
workersB = workersA.ToList();
foreach (var w in workersA.ToList())
{
workersC.Add(w);
}
您正在将workersA
中的相同Person
引用传递给workersC
。但它们都是指相同的Person
实例
因此,当你最终做到这一点时:
foreach (var p in workersA.ToList())
{
p.Age--;
}
每个人
实例的年龄
都会发生变化,尽管其中包含三个不同的列表
解决方案:
如果您确实想将不同的人员
传递给三个列表,一种方法是为人员
实现一个克隆
方法(您可以在IClonable
界面中找到):
然后,您可以使用克隆
而不是原始的人员
输入其他列表:
foreach (var w in workersA.ToList())
{
workersC.Add(w.Clone()); //use Clone here
}
根据
因为,归根结底,workersB
和workersC
中的每个元素都将指向您最初创建的单个Person
实例。因此,它们都引用相同的实例-因此得到了相同的结果
简而言之,您得到了三个不同的列表,其中包含三个相同的Person
实例
执行此操作时:
workersB = workersA.ToList();
foreach (var w in workersA.ToList())
{
workersC.Add(w);
}
您可以创建列表的新实例,而不是列表中单个对象的新实例。同样,当您这样做时:
workersB = workersA.ToList();
foreach (var w in workersA.ToList())
{
workersC.Add(w);
}
您正在将workersA
中的相同Person
引用传递给workersC
。但它们都是指相同的Person
实例
因此,当你最终做到这一点时:
foreach (var p in workersA.ToList())
{
p.Age--;
}
每个人
实例的年龄
都会发生变化,尽管其中包含三个不同的列表
解决方案:
如果您确实想将不同的人员
传递给三个列表,一种方法是为人员
实现一个克隆
方法(您可以在IClonable
界面中找到):
然后,您可以使用克隆
而不是原始的人员
输入其他列表:
foreach (var w in workersA.ToList())
{
workersC.Add(w.Clone()); //use Clone here
}
根据
由于类Person是reference type(),您的列表只包含对最初创建的Person实例的引用。当您更改任何列表中的实例时,每个列表中的实例都会更改。由于类Person是引用类型(),您的列表仅包含对最初创建的Person实例的引用。当您更改任何列表中的实例时,每个列表中的实例都会更改。您会得到相同的输出,因为您的Person
类是引用类型。因此,三个列表中的每一个都包含对相同对象的引用。因此,如果更改其中一个,那么也会更改其他两个列表中的相应元素,因为它们指向同一个元素。如果希望workersB
和workersC
包含独立元素,则必须复制它们。例如,添加一个副本构造函数
class Person {
....
public Person(Person other) {
this.Id = other.Id;
this.Name = other.Name;
...
}
}
当向workersB
和workersC
添加元素时,调用复制构造函数
foreach (Person p in workersA) {
workersB.Add(new Person(p));
workersC.Add(new Person(p));
}
或者作为另一种选择
workersB = workersA.Select(x=> new Person(x)).ToList();
workersC = workersA.Select(x=> new Person(x)).ToList();
这样,所有元素都是新对象,彼此不相关。由于您的Person
类是引用类型,因此您将获得相同的输出。因此,三个列表中的每一个都包含对相同对象的引用。因此,如果更改其中一个,那么也会更改其他两个列表中的相应元素,因为它们指向同一个元素。如果希望workersB
和workersC
包含独立元素,则必须复制它们。例如,添加一个副本构造函数
class Person {
....
public Person(Person other) {
this.Id = other.Id;
this.Name = other.Name;
...
}
}
当向workersB
和workersC
添加元素时,调用复制构造函数
foreach (Person p in workersA) {
workersB.Add(new Person(p));
workersC.Add(new Person(p));
}
或者作为另一种选择
workersB = workersA.Select(x=> new Person(x)).ToList();
workersC = workersA.Select(x=> new Person(x)).ToList();
这样,所有元素都是新对象,彼此不相关。为了隔离结果,需要创建单独的实例。实现的方法之一是在创建新列表时克隆实例
看看这个答案,它涵盖了相当全面的领域:
为了隔离结果,需要创建单独的实例。实现的方法之一是在创建新列表时克隆实例
看看这个答案,它涵盖了相当全面的领域:
@ShiftN'Tab啊,是的,你应该创建三个人的副本/克隆,而不是制作三个包含相同人的列表。一种简单的方法是,让Person
拥有Clone
方法,每次根据其自身属性创建新的Person
,然后通过克隆的Person
而不是原始的Person
将对其进行测试