简体   繁体   中英

How do you make a copy of an object?

I created a class called Colors. I am setting certain properties on the Colors object and setting it in a Session variable. When I access the Session variable on another page, I am noticing that if I change properties on objColors below, it changes the Session and does not keep the original properties which is what I want it to do. Here is an example:

Session["Colors"] = Colors;

Colors objColors = Session["Colors"];

//If I change objColors, it changes the Session.  I don't want this to happen.

Is there a better way to keep retain the original properties? Why does it do this?

Create a copy constructor for Colors. Then, do this.

Colors objColors = new Colors((Colors)Session["Colors"]);

In your new constructor, just copy the values that you need to and do your other constructor-related things.

What's happening in your code is that you are getting a pointer to a Colors object. Session["Colors"] and objColors point to the same object in memory, so when you modify one, changes are reflected in both. You want a brand spankin' new Colors object, with values initialized from objColors or Session["Colors"].

edit: A copy constructor might look like this:

public Colors(Colors otherColors)
{
    this.privateVar1 = otherColors.privateVar1;
    this.publicVar2 = otherColors.publicVar2;
    this.Init();
}

You can implement your own cloning methods to make a "copy" of an object. The reason this is happening is because the assignment of Colors objColors = Session["Colors"]; is a reference assignment, this is by design. All you are doing is making a local scope reference to an object that already exists. Take a look at IClonable for actual object cloning. This isn't necessary either you can implement your own copy methods. You may also want to take a look atMemberwiseClone depending on how deep your object goes.

Try a copy constructor.

Example: link

The object is being accessed by reference instead of by value. See here . There are several ways of changing this. Check out the site for detailed information.

Other answers have all suggested cloning in one way or another. An alternative which may or may not be suitable for your particular situation is to make your type immutable. Operations which previously mutated your type would now return a new instance of the type, taking data from the original object and making the appropriate changes, and leaving the original instance intact. This is the approach that the String class takes, for example.

You'll still have to write appropriate code to copy the data within an instance, of course - but the code working with the type may well end up being simpler.

This may well not be appropriate in your case, but it's a technique to at least consider.

There isn't a way built in and implemented by default, but you can get this by implementing ICloneable and calling MemberwiseClone. This will only work for a shallow copy -- if your object contains other objects, you'll need to clone them as well. A simple implementation would be:

public class Bla : ICloneable
{
    string _someFieldToClone;

    object ICloneable.Clone()
    {
        return this.Clone();
    }

    public Bla Clone()
    {
        return (Bla)MemberwiseClone();
    }
}

It does this because you are not actually copying the object but copying a reference to the object. You can do a deep copy in C# easily using Binary Serialization:

  public static MemoryStream Serialize(object data)
    {

        MemoryStream streamMemory = new MemoryStream();
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.AssemblyFormat = FormatterAssemblyStyle.Simple;

        formatter.Serialize(streamMemory, data);

        return streamMemory;


    }



   public static Object Deserialize(MemoryStream stream)
    {

        BinaryFormatter formatter = new BinaryFormatter();
        formatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
        return formatter.Deserialize(stream);

    }

You can call these two methods the first takes an object and writes its data to a MemoryStream. Then you can call Deserialize to get a new copy of an object based on that data.

One last thing your objects need to be Serializable do this by putting the Serializable attribute on each object.

When you have a variable and assign a session value to it, you are getting a pointer to both of them.

Colors objColors = (Colors)Session["Colors"];

Session["Colors"] and objColors point to the same object in memory, then when you made a change in one, changes are reflected in both.

If you want independence, need to get a Deep Copy of you object. You have to implement IClonable interface for Invoice and all of it 's related classes:

public class Colors: IClonable
{
  public int Red;
  public int Green;
  public int Blue;

  public object Clone()
  {
    return this.MemberwiseClone();
  }
}

Now you have a real deep copy of you invoice object.

Colors objColors = (Colors)((Colors)Session["Colors"]).Clone();

More information at: object cloning with IClonable and MemberwiseClone depending on how deep your object goes.

This is because the objColors and Session["Colors"] objects are the same object. If you want to store a copy and keep the original you need to make your object clonable.

See the following SO Q&A for a pointer in the right direction:

Deep cloning objects

Since the class Colors is one that you created, and I assume you're fairly new to object oriented programming, you can create a copy construtor like Stuart said with something similar to the following:

public class Colors
{
  public int Property1;
  public int Property2;
  public int Property3;
  public Colors()
  {
    //Do your regular constructor here
  }
  public Colors(Colors colorToCopy)
  {
    this.Property1 = colorToCopy.Property1;
    this.Property2 = colorToCopy.Property2;
    this.Property3 = colorToCopy.Property3;
  }
}

Cloning via serialization is a more generalized solution and ensures a deep copy (meaning it'll copy make the properties copies as well, as well as properties of properties) but is a little harder to understand imo. With this solution, if the Properties aren't primitive data types those wouldn't be copies unless you explicitly make them copies.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM