Deep copy ArrayList problem.

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Steven Blair

    Deep copy ArrayList problem.

    I need to perform a Deep Copy on an ArrayList.

    I wrote a small sample app to prove this could be done:

    ArrayList a = new ArrayList();
    ArrayList b = new ArrayList();

    a.Add("Hello");
    b = (ArrayList) a.Clone();

    a[0] = "World";

    This appears to work fine. However, when I try it in my application,
    both ArrayLists point to the same memory.

    Each element in my ArrayList is a custom class I have written, so I am
    wondering would this have any impact on the call to Clone() ?

    At a high level, what I need to do is create a very large structure once
    on startup (the ArrayList will be static) and when each request comes in
    from a client, I take a deep copy of the structure and allow each client
    their own working copy. This would cut down a massive amoutn of
    processing on my part.

    Can anyone help?

    Steven



    *** Sent via Developersdex http://www.developersdex.com ***
  • daa

    #2
    Re: Deep copy ArrayList problem.

    try:

    ArrayList a = new ArrayList();
    ArrayList b = new ArrayList();

    a.Add("Hello");
    b = a;


    Steven Blair wrote:
    I need to perform a Deep Copy on an ArrayList.
    >
    I wrote a small sample app to prove this could be done:
    >
    ArrayList a = new ArrayList();
    ArrayList b = new ArrayList();
    >
    a.Add("Hello");
    b = (ArrayList) a.Clone();
    >
    a[0] = "World";
    >
    This appears to work fine. However, when I try it in my application,
    both ArrayLists point to the same memory.
    >
    Each element in my ArrayList is a custom class I have written, so I am
    wondering would this have any impact on the call to Clone() ?
    >
    At a high level, what I need to do is create a very large structure once
    on startup (the ArrayList will be static) and when each request comes in
    from a client, I take a deep copy of the structure and allow each client
    their own working copy. This would cut down a massive amoutn of
    processing on my part.
    >
    Can anyone help?
    >
    Steven
    >
    >
    >
    *** Sent via Developersdex http://www.developersdex.com ***

    Comment

    • Chris Dunaway

      #3
      Re: Deep copy ArrayList problem.

      Steven Blair wrote:
      I need to perform a Deep Copy on an ArrayList.
      >
      I wrote a small sample app to prove this could be done:
      >
      ArrayList a = new ArrayList();
      ArrayList b = new ArrayList();
      >
      a.Add("Hello");
      b = (ArrayList) a.Clone();
      >
      a[0] = "World";
      >
      This appears to work fine. However, when I try it in my application,
      both ArrayLists point to the same memory.
      >
      I think you can use the ArrayList.CopyT o along with AddRange method:

      ArrayList a = new ArrayList();
      ArrayList b = new ArrayList();

      a.Add("Hello");

      string[a.Count] strings;
      a.CopyTo(string s);

      b.AddRange(stri ngs);

      Check the syntax, but I think this may work.

      Comment

      • Jon Skeet [C# MVP]

        #4
        Re: Deep copy ArrayList problem.

        Steven Blair <steven.blair@b tinternet.comwr ote:
        I need to perform a Deep Copy on an ArrayList.
        >
        I wrote a small sample app to prove this could be done:
        >
        ArrayList a = new ArrayList();
        ArrayList b = new ArrayList();
        >
        a.Add("Hello");
        b = (ArrayList) a.Clone();
        >
        a[0] = "World";
        >
        This appears to work fine. However, when I try it in my application,
        both ArrayLists point to the same memory.
        Could you post a short but complete program which demonstrates the
        problem?

        See http://www.pobox.com/~skeet/csharp/complete.html for details of
        what I mean by that.
        Each element in my ArrayList is a custom class I have written, so I am
        wondering would this have any impact on the call to Clone() ?
        Well, each list will refer to the same set of objects to start with,
        although the lists themselves are independent. If you want the objects
        themselves to be cloned (as your subject line suggests) you'll need to
        call Clone() on each of the objects, eg:

        for (int i=0; i < copiedList.Coun t; i++)
        {
        copiedList[i] = copiedList[i].Clone();
        }

        --
        Jon Skeet - <skeet@pobox.co m>
        http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
        If replying to the group, please do not mail me too

        Comment

        • Jon Skeet [C# MVP]

          #5
          Re: Deep copy ArrayList problem.

          daa <mithunster@gma il.comwrote:
          try:
          >
          ArrayList a = new ArrayList();
          ArrayList b = new ArrayList();
          >
          a.Add("Hello");
          b = a;
          That ends up with a single list, with two variables referring to the
          same list. In fact, assigning a new ArrayList reference to b to start
          with is pointless.

          --
          Jon Skeet - <skeet@pobox.co m>
          http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
          If replying to the group, please do not mail me too

          Comment

          • Steven Blair

            #6
            Re: Deep copy ArrayList problem.

            Thanks for the replies.

            Here is an example which closely matches the problem:

            static void Main(string[] args)
            {
            ArrayList a = new ArrayList();
            ArrayList b = new ArrayList();

            a.Add( new ExampleClass("H ello") );
            b = (ArrayList) a.Clone(); //I expected this to clone the whole
            structure.

            ((ExampleClass) a[0]).m_Value = "World"; //This changes b[0] as well!
            }

            public class ExampleClass
            {
            public string m_Value;

            public ExampleClass(st ring s)
            {
            m_Value = s;
            }

            public override string ToString()
            {
            return m_Value;
            }
            }



            *** Sent via Developersdex http://www.developersdex.com ***

            Comment

            • Steven Blair

              #7
              Re: Deep copy ArrayList problem.

              Jon,

              Since each class is custom, I can only call Clone on the ArrayList
              itself:

              a.Clone();

              and not

              a[i].Clone();


              *** Sent via Developersdex http://www.developersdex.com ***

              Comment

              • Frans Bouma [C# MVP]

                #8
                Re: Deep copy ArrayList problem.

                Steven Blair wrote:
                I need to perform a Deep Copy on an ArrayList.
                >
                I wrote a small sample app to prove this could be done:
                >
                ArrayList a = new ArrayList();
                ArrayList b = new ArrayList();
                >
                a.Add("Hello");
                b = (ArrayList) a.Clone();
                >
                a[0] = "World";
                >
                This appears to work fine. However, when I try it in my application,
                both ArrayLists point to the same memory.
                >
                Each element in my ArrayList is a custom class I have written, so I am
                wondering would this have any impact on the call to Clone() ?
                >
                At a high level, what I need to do is create a very large structure
                once on startup (the ArrayList will be static) and when each request
                comes in from a client, I take a deep copy of the structure and allow
                each client their own working copy. This would cut down a massive
                amoutn of processing on my part.
                >
                Can anyone help?
                MemoryStream stream = new MemoryStream();
                BinaryFormatter formatter = new BinaryFormatter ();
                formatter.Seria lize(stream, a);
                stream.Seek(0, SeekOrigin.Begi n);
                ArrayList b = (ArrayList)form atter.Deseriali ze(stream);
                stream.Close();
                stream.Dispose( );

                This gives you perfectly deep copies of a complete object graph.

                (disclaimer: written from my bare head so it might have some small
                syntax errors here and there)

                FB

                --
                ------------------------------------------------------------------------
                Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
                LLBLGen Pro website: http://www.llblgen.com
                My .NET blog: http://weblogs.asp.net/fbouma
                Microsoft MVP (C#)
                ------------------------------------------------------------------------

                Comment

                • Steven Blair

                  #9
                  Re: Deep copy ArrayList problem.

                  Frans,

                  Thanks for the reply.

                  Is this code a hit on performance?

                  I need to determine if creating a deep copy is more expensive than
                  actually building the structure from scratch each time.

                  My original structure has seem times of >50ms to construct!



                  *** Sent via Developersdex http://www.developersdex.com ***

                  Comment

                  • Jon Skeet [C# MVP]

                    #10
                    Re: Deep copy ArrayList problem.

                    Steven Blair wrote:
                    Thanks for the reply.
                    >
                    Is this code a hit on performance?
                    Yes, that will be a hit on performance.
                    I need to determine if creating a deep copy is more expensive than
                    actually building the structure from scratch each time.
                    >
                    My original structure has seem times of >50ms to construct!
                    A much better idea than serialization *if* you're in control of all the
                    objects is to implement your own Clone method, and invoke it on each of
                    the objects in the list.

                    Jon

                    Comment

                    • Steven Blair

                      #11
                      Re: Deep copy ArrayList problem.

                      Ok, using the example above, here is what I think the finished code
                      looks like:

                      static void Main(string[] args)
                      {
                      ArrayList a = new ArrayList();
                      ArrayList b = new ArrayList();

                      ExampleClass t = new ExampleClass("H ello");

                      a.Add( t );

                      //At this point, I would loop round the count of the ArrayList
                      b.Add( ((ExampleClass) a[0]).Clone() );

                      ((ExampleClass) a[0]).m_Value = "World";
                      }

                      public class ExampleClass : ICloneable
                      {
                      public string m_Value;

                      public ExampleClass(st ring s)
                      {
                      m_Value = s;
                      }

                      public override string ToString()
                      {
                      return m_Value;
                      }

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

                      public virtual ExampleClass Clone()
                      {
                      return this.Memberwise Clone() as ExampleClass;
                      }
                      }

                      Any final comments?



                      *** Sent via Developersdex http://www.developersdex.com ***

                      Comment

                      • Jon Skeet [C# MVP]

                        #12
                        Re: Deep copy ArrayList problem.


                        Steven Blair wrote:
                        Ok, using the example above, here is what I think the finished code
                        looks like:
                        >
                        static void Main(string[] args)
                        {
                        ArrayList a = new ArrayList();
                        ArrayList b = new ArrayList();
                        >
                        ExampleClass t = new ExampleClass("H ello");
                        >
                        a.Add( t );
                        >
                        //At this point, I would loop round the count of the ArrayList
                        b.Add( ((ExampleClass) a[0]).Clone() );
                        >
                        ((ExampleClass) a[0]).m_Value = "World";
                        }
                        Yup, that would be fine - except you could just use a foreach on the
                        loop, rather than using Count explictly.

                        Of course, MemberwiseClone only gives a shallow copy too - you'll need
                        to clone in an appropriate way for each class. Note that casting to
                        ICloneable instead of ExampleClass would be more flexible.

                        Jon

                        Comment

                        • Steven Blair

                          #13
                          Re: Deep copy ArrayList problem.

                          Now I am confused.
                          My testing appears to show a deep copy is taking place, so how can the
                          MemberwiseClone only give me a shallow copy?

                          This line of code:

                          ((ExampleClass) a[0]).m_Value = "World";

                          Changes object a, but b is unchanged.

                          Good point regarding the casting. I have now updated that.

                          I double check the code, and I do appear to have 2 seperate classes
                          after using the Clone().





                          *** Sent via Developersdex http://www.developersdex.com ***

                          Comment

                          • Marc Gravell

                            #14
                            Re: Deep copy ArrayList problem.

                            Because it clones the fields essentially as a memcopy operation. For
                            value-type fields (numerics etc) this is fine. However, for reference-types
                            (custom classes, or lists, collections, arrays etc) you will simply clone
                            the *pointer* to the actual class on the heap, so to get a true "deep" clone
                            you would have to keep going. Note that for immutable reference types (such
                            as string) you won't really notice the difference.

                            It is unfortunate that IClonable doesn't distinguish between shallow and
                            deep.

                            Marc



                            Comment

                            • Steven Blair

                              #15
                              Re: Deep copy ArrayList problem.

                              oh, now I understand:

                              public class ExampleClass : ICloneable
                              {
                              public string m_Value;
                              public ArrayList m_Names; // :( shallow copy time

                              public ExampleClass(st ring s)
                              {
                              m_Value = s;
                              m_Names = new ArrayList();
                              }

                              public override string ToString()
                              {
                              return m_Value;
                              }

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

                              public virtual ICloneable Clone()
                              {
                              return this.Memberwise Clone() as ICloneable;
                              }
                              }

                              m_Names would be a shallow copy :(

                              This is realy not good. It seems extremely complicated to copy (deep)
                              structures in C#.

                              I think living with the slow structure construction time is the only
                              option for me at the moment.

                              Thanks for the help everyone.



                              *** Sent via Developersdex http://www.developersdex.com ***

                              Comment

                              Working...