开发者

C# Returning object from Array leaves pointer to Array item

开发者 https://www.devze.com 2022-12-16 01:26 出处:网络
I have a List<T> and I do the following: var myObj = List[2];//Return object at position 2 myObj.Name = \"fred\";//If you look at List[2] its name has changed to fred

I have a List<T> and I do the following:

var myObj = List[2];  //Return object at position 2
myObj.Name = "fred";  //If you look at List[2] its name has changed to fred

I tried the following but it still updates the item in the List

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

How can I avoid this pointer remaining so I can update properties without it updating it in the 开发者_Python百科list?


You could make your object implement the ICloneable interface using the MemberwiseClone method and then:

var myObj = List[2];
var newObj = myObj.Clone();
newObj.Name = "fred";

UPDATE:

As pointed out in the comments section it is not recommended to implement the ICloneable interface as it does not specify if it will perform a shallow or deep clone. Just add a Clone method to your class.


This has nothing to do with arrays or lists per se - it's just how reference types work. Here's a simpler demonstration:

MyObj a = new MyObj();
MyObj b = a;
a.Name = "Test";
Console.WriteLine(b.Name); // Will print "Test"

Lists and arrays work the same way - the values stored will be references (assuming they're reference type values) rather than the data for the object itself.

You might want to read my article about reference types and value types for more information.

As others have said, if you really want independent objects you'll need to clone them. I would suggest trying to design around this in another way though, personally.


Jon. In C# the items in your array are stored 'by reference', meaning that you do not hold a copy of the object in the array you hold a reference (a 'pointer') to it. When you retrieve the element you are retrieving the reference, so you now have two references to the same object. As you only have one object when you update the value both references 'see' the new value. To avoid this you need to copy the instance and there are a couple of ways to do this. As Darin mentioned you could have the object implement ICloneable you could also and the object implement a copy constructor, or you could create a new object and populate the new one from the 'old' data. However, be aware that there are issues, the primary one being the problem of 'deep copy'. If your object holds references to other objects, how do you copy those? do you copy the reference or do you chase the references down and 'deep copy' those. There is no single answer to this, just the classic 'it depends!'


What exactly do you want to do anyway? Do you want to update the property of the object in the list, or do you want another object which is a copy of the object in the list but with a different name?

As an alternative to providing a clone method you could provide a copy constructor.

var newObj = new MyObj(List[2]);
newObj.Name = "fred";

you might be able to do this in a single call, depending on what you want to do. If you know you are always going to create a copy with just a different name then you might want to do something like

var newObj = new MyObj(List[2],"fred");

and set the name during the construction.

but without explicitly creating a new object in some way you can't do what you want.

Be aware though that if you object has a property which is anther object, that you might get into the 'deep copy' problem (which is why IClonable is discouraged) as what do you do when you need to copy that object in you newObj? Do you just provide a reference to the same instance? Or do you copy that as well? What if that object has no clone method/copy constructor, what do you do then?


Great comments, thanks but this is what I have implemented:

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;
    }
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号