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#从数组返回对象留下指向数组项的指针的主要内容,如果未能解决你的问题,请参考以下文章

从 C++ 中的函数返回指向数组的指针?

C ++从函数返回指向数组的指针的正确方法

从函数返回指向数组的指针,函数名称后具有数组维度

从指向函数指针数组的指针中存储返回值如何工作?

js 二分查找(Binary Search)

C语言基础:C 中数组详解(多维数组传递数组给函数 从函数返回数组 指向数组的指针 )