我正在使用此例程将一些坐标加载到容器中,绘制它们,放大它们以及这些任务。然后在按钮单击时,我倾向于重置所有内容到原始状态或初始状态。要做到这一点,我拿一份初始版本并播放副本。但是在重置按钮单击时,我销毁副本,获取初始副本并处理它。等等。
由于某种原因,我更改副本时原始容器会更改。谁能发现我做错了什么?
按顺序,我先加载数据并复制一份:
// CoordPoint is a simple xy point
public List<CoordPoint> MyLoadedCoords { get { return myLoadedCoords; } set { myLoadedCoords = value; }}
public List<CoordPoint> MyDisplayedCoords { get { return myDisplayedCoords; } set { myDisplayedCoords = value }}
private List<CoordPoint> myLoadedCoords;
private List<CoordPoint> myDisplayedCoords;
//..
public void LoadData()
{
// load points from file
MyLoadedCoords = File.ReadLines("C:\\...\\Samples.txt")
// get a copy of original coords
MyDisplayedCoords = MyLoadedCoords.ToList();
}
请注意,此处代码中MyLoadedCoords
存在 no where (并且在Reset函数中,向下)。然后我处理副本MyDisplayedCoords
几个与此类似的地方:
public void UpdateDisplayPosition()
{
for (var i = 0; i < MyDisplayedCoords.Count; i++)
{
MyDisplayedCoords[i].X += XCoordOffset; //some processed values
MyDisplayedCoords[i].Y += YCoordOffset; //some processed values
}
}
重置按钮我这样做:
public void ResetZoom()
{
MyDisplayedCoords = MyLoadedCoords.ToList(); // I set break point here
AdjustInitialDisplayPosition();
DrawImage();
}
ResetZoom()
没有达到预期效果,当我调试并中断MyDisplayedCoords = MyLoadedCoords;
时,我发现MyLoadedCoords
包含与MyDisplayedCoords
完全相同的值/对象
修改
我实施了IClonable
并“覆盖”了我班级中的Clone()
功能,但它确实不工作:
public class CoordPoint : ICloneable
{
// ..
public object Clone()
{
return new CoordPoint {X = X, Y = Y, Z = Z, Color = Color};
}
}
但是, out IClonable
,此“复制”工作克隆为H.B已回答:
MyDisplayedCoords = MyLoadedCoords.Select(c => new CoordPoint { X = c.X, Y = c.Y, Z = c.Z, Color = c.Color }).ToList();
答案 0 :(得分:5)
MyDisplayedCoords = MyLoadedCoords
不会复制任何内容,它会将同一个对象的引用分配给属性,现在这两个属性都指向同一个对象。
要复制可以使用Linq方法的列表(它总是返回一个新列表):
MyDisplayedCoords = MyLoadedCoords.ToList();
要进行深层复制,您可以执行类似的操作,然后列表中的实例也会有所不同:
MyDisplayedCoords = MyLoadedCoords.Select(c =>
new CoordPoint { X = c.X, Y = c.Y }).ToList();
答案 1 :(得分:2)
添加H.B的答案,
ToList
创建一个新的List
对象,但列表中的对象只是对同一object
的引用,除非它们是不可变对象(例如字符串或原始类型) )。
在这种情况下,您的原始List
对象不会受到影响(添加新对象/删除等),但对象的更改将反映在两者中。因为他们引用相同的对象。
您可以按照H.B的回答将新复制品作为新对象复制,也可以按照以下流程进行更清晰,更合理。
在ICloneable
课程中实施CoordPoint
界面。覆盖Clone
方法并在复制期间调用它。有点长的方法,但这样你的代码Linq
看起来会很合适。
public class CoordPoint : ICloneable
{
//rest of your code here
public object Clone()
{
return new CoordPoint
{
X= X,
Y = Y
};
}
}
然后您的Linq
代码将是,
MyDisplayedCoords = MyLoadedCoords.Select(c => (CoordPoint)c.Clone()).ToList();
答案 2 :(得分:0)
当你复制&#39;您的列表对象是一个新的列表,但该列表中的项目仍然指向与第一个相同的项目。
解决此问题的最简单方法是ICloneable
界面,这是一个简短的示例:
public class MyObject : ICloneable
{
public string Property { get; set; }
public object Clone()
{
return this.MemberwiseClone();
}
}
用法:
var list = new List<MyObject>() { new MyObject { Property = "FirstObject" } };
var clonedList = list.Select(x => x.Clone());