C#从数组返回对象留下指向数组项的指针
Posted
技术标签:
【中文标题】C#从数组返回对象留下指向数组项的指针【英文标题】:C# Returning object from Array leaves pointer to Array item 【发布时间】:2011-01-04 13:42:50 【问题描述】:我有一个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
我怎样才能避免这个指针残留,这样我就可以在不更新列表的情况下更新属性?
【问题讨论】:
【参考方案1】:您可以使用MemberwiseClone 方法让您的对象实现ICloneable 接口,然后:
var myObj = List[2];
var newObj = myObj.Clone();
newObj.Name = "fred";
更新:
正如 cmets 部分所指出的,不建议实现 ICloneable
接口,因为它没有指定执行浅克隆还是深层克隆。只需在您的类中添加一个 Clone
方法即可。
【讨论】:
框架设计指南建议不要实现 ICloneable 接口。只需提供一个Clone
方法即可。
克隆的想法是正确的,但不要实现ICloneable。详情请见blogs.msdn.com/brada/archive/2003/04/09/49935.aspx。
有没有一种快速的方法可以将所有属性复制到新对象,而不是手动显式键入所有属性,以防万一类获得新属性并且克隆方法忘记添加该属性以进行复制.
见MemberwiseClone
方法。【参考方案2】:
这与数组或列表本身无关——这只是引用类型的工作方式。这是一个更简单的演示:
MyObj a = new MyObj();
MyObj b = a;
a.Name = "Test";
Console.WriteLine(b.Name); // Will print "Test"
列表和数组的工作方式相同 - 存储的值将是 references(假设它们是引用类型值)而不是对象本身的数据。
您可能想阅读我的article about reference types and value types 了解更多信息。
正如其他人所说,如果你真的想要独立的对象,你需要克隆它们。不过,我个人建议尝试以另一种方式围绕此进行设计。
【讨论】:
【参考方案3】:乔恩。在 C# 中,数组中的项目是“按引用”存储的,这意味着您不持有数组中对象的副本,而是持有对它的引用(“指针”)。当您检索元素时,您正在检索引用,因此您现在有两个对同一对象的引用。因为当您更新值时只有一个对象,所以两个引用都“看到”新值。为避免这种情况,您需要复制实例,并且有几种方法可以做到这一点。正如 Darin 提到的,您可以让对象实现 ICloneable,您也可以让对象实现复制构造函数,或者您可以创建一个新对象并从“旧”数据填充新对象。但是,请注意存在一些问题,主要是“深拷贝”问题。如果您的对象包含对其他对象的引用,您如何复制这些?你是复制参考还是追逐参考并“深度复制”那些。对此没有单一的答案,只有经典的“视情况而定!”
【讨论】:
【参考方案4】:你到底想做什么?您想更新列表中对象的属性,还是想要另一个对象,它是列表中对象的副本但名称不同?
作为提供克隆方法的替代方法,您可以提供复制构造函数。
var newObj = new MyObj(List[2]);
newObj.Name = "fred";
您可以在一次调用中完成此操作,具体取决于您想要执行的操作。如果你知道你总是要创建一个只有不同名称的副本,那么你可能想要做类似的事情
var newObj = new MyObj(List[2],"fred");
并在构建过程中设置名称。
但是如果不以某种方式明确地创建一个新对象,你就不能做你想做的事。
请注意,如果您的对象具有另一个对象的属性,您可能会遇到“深拷贝”问题(这就是不鼓励使用 IClonable 的原因),因为当您需要将该对象复制到你新对象?您是否只提供对同一实例的引用?或者你也复制它?如果那个对象没有克隆方法/复制构造函数怎么办?
【讨论】:
【参考方案5】:很棒的 cmets,谢谢,但这是我已经实现的:
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;
【讨论】:
以上是关于C#从数组返回对象留下指向数组项的指针的主要内容,如果未能解决你的问题,请参考以下文章