我有一个List<T>
,我会执行以下操作:
var myObj = List[2]; //Return object at position 2
myObj.Name = "fred"; //If you look at List[2] its name has changed to fred
我尝试了以下操作,但它仍然更新列表中的项目
var newObj = new MyObj();
var myObj = List[2]; //Return object at position 2
newObj = myObj;
newObj.Name = "fred"; //If you look at List[2] its name has still changed to fred
如何避免此指针保留,以便我可以在不更新列表的情况下更新属性?
答案 0 :(得分:3)
您可以使用ICloneable方法使对象实现MemberwiseClone界面,然后:
var myObj = List[2];
var newObj = myObj.Clone();
newObj.Name = "fred";
更新:
正如评论部分所指出的,不建议实现ICloneable
接口,因为它没有指定它是执行浅或深克隆。只需在您的班级中添加Clone
方法即可。
答案 1 :(得分:2)
这与数组或列表本身无关 - 它只是引用类型的工作方式。这是一个更简单的演示:
MyObj a = new MyObj();
MyObj b = a;
a.Name = "Test";
Console.WriteLine(b.Name); // Will print "Test"
列表和数组的工作方式相同 - 存储的值将是引用(假设它们是引用类型值),而不是对象本身的数据。
您可能需要阅读我的article about reference types and value types以获取更多信息。
正如其他人所说,如果你真的想要独立的对象,你需要克隆它们。我建议尝试以另一种方式围绕这个设计,但是,个人。
答案 2 :(得分:1)
你究竟想做什么?是否要更新列表中对象的属性,或者是否需要另一个对象,该对象是列表中对象的副本,但名称不同?
作为提供克隆方法的替代方法,您可以提供复制构造函数。
var newObj = new MyObj(List[2]);
newObj.Name = "fred";
您可以在一次通话中执行此操作,具体取决于您要执行的操作。如果您知道您总是要创建一个只有不同名称的副本,那么您可能想要执行类似
的操作var newObj = new MyObj(List[2],"fred");
并在施工期间设置名称。
但如果没有以某种方式明确创建新对象,则无法执行所需操作。
请注意,如果你的对象有一个属于另一个对象的属性,你可能会遇到“深层复制”问题(这就是为什么不鼓励IClonable),就像你需要复制那个对象时那样做你newObj?您是否只提供对同一实例的引用?或者你也复制它?如果该对象没有克隆方法/复制构造函数,那么该怎么办?
答案 3 :(得分:1)
乔恩。在C#中,数组中的项目是“通过引用”存储的,这意味着您不会在数组中保存对象的副本,而是包含对它的引用(“指针”)。当您检索要检索引用的元素时,现在您有两个对同一对象的引用。由于在更新值时只有一个对象,因此两个引用都会“看到”新值。为避免这种情况,您需要复制实例,并且有几种方法可以执行此操作。正如Darin所提到的,你可以让对象实现ICloneable,你也可以和对象实现一个复制构造函数,或者你可以创建一个新对象并从'旧'数据中填充新对象。但是,请注意存在问题,主要问题是“深层复制”。如果您的对象包含对其他对象的引用,您如何复制它们?你复制了参考文献,或者你追溯参考文献和'深层复制'那些参考文献。对此没有单一的答案,只有经典的“它取决于!”
答案 4 :(得分:1)
很棒的评论,谢谢,但这是我实施的:
public MyObj Clone()
{
BinaryFormatter bFormatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
bFormatter.Serialize(stream, this);
stream.Seek(0, SeekOrigin.Begin);
MyObj newObj = (MyObj)bFormatter.Deserialize(stream);
return newObj;
}