我有一个叫做粒子的物体,它有自己的属性(位置,速度等),在我的窗体中,我创建了一个粒子列表。然后在代码中更新该粒子列表(即,在每个迭代步骤中更新每个粒子的位置,速度等)。
我想要做的是每次迭代(点击一个按钮后)将此List<Particle>
添加到另一个列表List<List<Particle>>
,以便我现在可以单独列出可以比较的粒子列表。
这是我的代码看起来的样子(UpdateEngine是一个在其初始化方法中创建粒子列表的类,然后有其他方法更新其列表中粒子的值):
public partial class frmMain : Form
{
private List<List<Particle>> listPlist;
private UpdateEngine Engine;
...
public frmMain()
{
InitializeComponent();
listPlist = new List<List<Particle>>();
Engine = new UpdateEngine();
}
...
//pressing this button iterates through a specified number of iterations
private void btPrep_Click(object sender, EventArgs e)
{
//create the particles and add the first list to the list of lists
Engine.Initialize();
listPlist.Add(Engine.ParticleList);
//iterate through the list of particles in Engine and update their properties
for(i = 0; i <= iterations; i++)
{
Engine.Update();
listPlist.Add(Engine.ParticleList);
}
}
}
我看到的是在迭代之前添加第一个列表。在for循环中添加的第一个列表被添加正常。之后添加的每个列表都会将listPlist中的所有列表更改为与当前列表相同。
我在运行代码时看到的一个例子:
初始化后:
第一次迭代后:
下一次迭代后:
我真的不确定如何解决这个问题。有谁知道为什么会这样?
答案 0 :(得分:3)
根据我对您的问题的理解,问题是您正在尝试制作参考项目的副本,这就是您看到所有列表项目发生变化的原因。
您需要对这些列表/粒子进行深度克隆,以便它们不依赖于参考。
您可能必须向粒子对象添加新的复制方法或构造函数才能实现此目的。
像
这样的东西public class Particle
{
public int SomeField;
public Particle Copy()
{
return new Particle { SomeField = this.SomeField };
}
public Particle(Particle copyFrom)
{
this.SomeField = copyFrom.SomeField;
}
}
然后,您可以创建原始列表的副本,如
List<Particle> copyList = new List<Particle>(originalList.Select(c => c.Copy));
答案 1 :(得分:0)
答案实际上取决于Engine.Update
的作用。如果它更新ParticleList
并使用新的Particle
值填充它,您只需在循环内外进行以下更改(复制列表):
listPlist.Add(new List<ParticleList>(Engine.ParticleList));
但是,如果Engine.Update
仅更新相同Particle
个对象的内部值,则您需要通过复制列表以及Particle
来制作深层副本。像其他人所说的内部对象。
答案 2 :(得分:0)
您遇到的是因为List<>
对象仅指向基础Particle
对象。如果相同的粒子在两个(或更多)不同的列表中并且它发生变化,无论您是从一个列表还是从其他列表访问粒子,您都指向已更改的对象。
这就像说“鲍勃史密斯”在电话簿中,也住在一所房子里。让我们说你去他家切断鲍勃的腿,如果你打电话给鲍勃(不是以同样的方式接触他)他仍然会双腿失踪!
就像@astander所说,你可以在Particle
类中创建一个方法来创建所谓的对象深度克隆。该方法很可能将原始对象的所有属性(和字段)复制到新对象中。但是你必须要小心:如果Particle
有一个SubParticle
类型的字段(或任何其他对象),当你进行深度克隆时,你可能也希望对该对象进行深度克隆否则你的两个Particle
(原件和副本)都会指向相同的SubParticle
。
另外,在您的特定上下文中,我建议您在循环的每次迭代后,创建一个新的粒子副本列表。如果您随后从列表中删除了一个粒子,GarbageCollector
只会在不再引用它的情况下处理它。
编辑:通过重新阅读您的代码,我得出以下结论:在您的Engine.Update()方法中,您可以从创建新的副本列表开始。这意味着在每次和每次Engine.Update()调用之后,您的粒子不是同一个对象。为此,首先实现一个返回深度克隆的Particle.Copy()方法,并通过执行以下操作启动Engine.Update():
ParticleList = new List<Particle>(ParticleList.Select(p=>p.Copy()));