By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
429,078 Members | 2,159 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 429,078 IT Pros & Developers. It's quick & easy.

Deep copy ArrayList problem.

P: n/a
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 ***
Nov 20 '06 #1
Share this Question
Share on Google+
22 Replies


P: n/a
daa
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 ***
Nov 20 '06 #2

P: n/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.
I think you can use the ArrayList.CopyTo along with AddRange method:

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

a.Add("Hello");

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

b.AddRange(strings);

Check the syntax, but I think this may work.

Nov 20 '06 #3

P: n/a
Steven Blair <st**********@btinternet.comwrote:
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.Count; i++)
{
copiedList[i] = copiedList[i].Clone();
}

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 20 '06 #4

P: n/a
daa <mi********@gmail.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 - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 20 '06 #5

P: n/a
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("Hello") );
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(string s)
{
m_Value = s;
}

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

*** Sent via Developersdex http://www.developersdex.com ***
Nov 21 '06 #6

P: n/a
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 ***
Nov 21 '06 #7

P: n/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?
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, a);
stream.Seek(0, SeekOrigin.Begin);
ArrayList b = (ArrayList)formatter.Deserialize(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#)
------------------------------------------------------------------------
Nov 21 '06 #8

P: n/a
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 ***
Nov 21 '06 #9

P: n/a
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

Nov 21 '06 #10

P: n/a
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("Hello");

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(string s)
{
m_Value = s;
}

public override string ToString()
{
return m_Value;
}

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

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

Any final comments?

*** Sent via Developersdex http://www.developersdex.com ***
Nov 21 '06 #11

P: n/a

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("Hello");

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

Nov 21 '06 #12

P: n/a
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 ***
Nov 21 '06 #13

P: n/a
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

Nov 21 '06 #14

P: n/a
oh, now I understand:

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

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

public override string ToString()
{
return m_Value;
}

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

public virtual ICloneable Clone()
{
return this.MemberwiseClone() 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 ***
Nov 21 '06 #15

P: n/a
Is this how I would deep copy an ArrayList inside my custom class:

public class ExampleClass : ICloneable
{
public string m_Value;
public ArrayList m_Names;

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

public override string ToString()
{
return m_Value;
}

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

public virtual ICloneable Clone()
{
ExampleClass x = this.MemberwiseClone() as ExampleClass;

//This is how I would Clone reference type?
x.m_Names = this.m_Names.Clone() as ArrayList;

return x as ICloneable;
}
}

This does seem to work, but would like to double check.

My custom class in the production software is mainly made up of string,
int, bool and enum. A few methods and an ArrayList. As far as I can see,
the ArrayList is the only object that would be a shallow copy?

Hopefully this is case closed this time!

*** Sent via Developersdex http://www.developersdex.com ***
Nov 21 '06 #16

P: n/a
"Steven Blair" <st**********@btinternet.comwrote in message
news:Oy**************@TK2MSFTNGP02.phx.gbl...
This does seem to work, but would like to double check.
Try:
public class ExampleClass : ICloneable
{
public string m_Value;
public ArrayList m_Names;

public ExampleClass(string s, ArrayList a)
{
m_Value = s;
m_Names = a;
}

public ExampleClass() { }

public override string ToString()
{
return m_Value;
}

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

public virtual ExampleClass Clone()
{
ExampleClass result = new ExampleClass();
if (m_Names != null)
{
result.m_Names = new ArrayList();
foreach (object o in m_Names)
{
result.m_Names.Add(o); //again, if o are reference types you'll have to
make your own clone
}
}

return result;
}
}

Cheers!

Chris.
Nov 21 '06 #17

P: n/a
Chris,

o is reference type.

I assumed the code I had in there would do the deep copy now?

*** Sent via Developersdex http://www.developersdex.com ***
Nov 21 '06 #18

P: n/a
"Steven Blair" <st**********@btinternet.comwrote in message
news:OW**************@TK2MSFTNGP06.phx.gbl...
Chris,

o is reference type.

I assumed the code I had in there would do the deep copy now?
Both reference types and value types derive from object.

ArrayList.Clone() produces a shallow copy. If you want a deep copy you'll
have to create another instance (memory reference) and copy the members
across, cloning the reference types as necessary.

Don't forget that shallow copy means referring to the same instance, whereas
a deep copy is a difference instance.
e.g.

ExampleClass one = new ExampleClass;
ExampleClass two = one;

both two and one refer to the same instance ("shallow").

ExampleClass one = new ExampleClass;
ExampleClass two = new ExampleClass;

one and two are different instances ("deep").

Cheers!

Chris.
Nov 21 '06 #19

P: n/a
"Christopher Ireland" <ci******@gmail.comwrote in message
news:u7**************@TK2MSFTNGP06.phx.gbl...
"Steven Blair" <st**********@btinternet.comwrote in message
news:OW**************@TK2MSFTNGP06.phx.gbl...
>Chris,

o is reference type.

I assumed the code I had in there would do the deep copy now?

Both reference types and value types derive from object.

ArrayList.Clone() produces a shallow copy. If you want a deep copy you'll
have to create another instance (memory reference) and copy the members
across, cloning the reference types as necessary.
You might find this article helpful in understanding what's going on:
http://www.c-sharpcorner.com/UploadF...rp_memory.aspx

Cheers!

Chris.
Nov 21 '06 #20

P: n/a
Steven.. To be clear Clone on a string simply returns a new reference to
the same string.

http://msdn.microsoft.com/library/de.../en-us/dnguine
t/html/drguinet5_update.asp

When is Clone not Clone?
But what if you want to have two separate strings, each containing the
same value? Well, generally you do not want this. Why waste the memory?
And because strings are immutable, there's not much point in having two
separate strings that have the same value.

So, although String implements IClonable, String.Clone simply returns a
reference to the same string without cloning it.

All is not lost, however: You can use the static method Copy if you
insist on having a second copy of the string.
Regards,
Jeff

*** Sent via Developersdex http://www.developersdex.com ***
Nov 21 '06 #21

P: n/a
Yup, I understand this. But my lasy query is to do with this line:

x.m_Names = this.m_Names.Clone() as ArrayList;

m_Names is an ArrayList and I am looking for confirmation that the last
class I posted would be a compleye deep copy?

I think I have everything covered now (one string and one ArrayList).

*** Sent via Developersdex http://www.developersdex.com ***
Nov 22 '06 #22

P: n/a
Steven Blair wrote:
Frans,

Thanks for the reply.

Is this code a hit on performance?
depends on the graph. It takes performance of course, however it also
works no matter what graph you have. It can be an option if you have to
work with object instances of classes you don't control.

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#)
------------------------------------------------------------------------
Nov 22 '06 #23

This discussion thread is closed

Replies have been disabled for this discussion.