copy ctore, assignment operator and Clone() - dang!

  • Thread starter Thread starter Steve
  • Start date Start date
S

Steve

I can't find a straight answer on what to use? I need a deep copy, so I
implemented IConeable and the Clone() method. However, I'm not sure I did
it correct. Is it suposed to be an allocation of a new object, then the
assignment of each member? Is that all or is there something else I need to
do?

Here is my code
<code>
public Object Clone()
{
BOLDeviceProtocol newObject = new BOLDeviceProtocol();

newObject.m_custom = this.m_custom;
newObject.m_dal = this.m_dal;
newObject.m_deviceProtocolID = this.m_deviceProtocolID;
newObject.m_deviceSettingsID = this.m_deviceSettingsID;
newObject.m_duration = this.m_duration;
newObject.m_enabled = this.m_enabled;
newObject.m_isDirty = this.m_isDirty;
newObject.m_protocolID = this.m_protocolID;
newObject.m_protocolName = this.m_protocolName;
newObject.m_protocolNumber = this.m_protocolNumber;
newObject.m_segments = new BOLProtocolSegmentList();
foreach(BOLProtocolSegment segment in this.m_segments)
{
newObject.m_segments.Add(segment);
}

return newObject;
}
</code>



How do I know that m_segments.Add() is creating a deep copy of segment?

I'm just looking for a little verification.

Thanks,
Steve
 
That depends upon the implementation of BOLProtocolSegmentList. If
BOLProtocolSegmentList.Add is defined to clone the object before adding
the clone to the list, then yes, your Clone() method is cloning the
segments because it's calling the Add() method, which is designed to
clone before it adds.

However, that's a really bad design.

More likely (and more correctly), the Add method of
BOLProtocolSegmentList should not clone before it adds. It should just
add whatever it's given to the list. In that case, you have to do the
Clone yourself, if you want a deep copy:

newObject.m_segments.Add(segment.Clone());

and yes, this means that BOLProtocolSegment must implement ICloneable,
too.
 
Bruce Wood said:
That depends upon the implementation of BOLProtocolSegmentList. If
BOLProtocolSegmentList.Add is defined to clone the object before adding
the clone to the list, then yes, your Clone() method is cloning the
segments because it's calling the Add() method, which is designed to
clone before it adds.

However, that's a really bad design.

More likely (and more correctly), the Add method of
BOLProtocolSegmentList should not clone before it adds. It should just
add whatever it's given to the list. In that case, you have to do the
Clone yourself, if you want a deep copy:

newObject.m_segments.Add(segment.Clone());

and yes, this means that BOLProtocolSegment must implement ICloneable,
too.

Thank you for the response, Bruce. It's taking a little time to get my head
around the details for reference/value types. It was really nice and easy
when I didn't care, but now that I need to worry about it, it's a little
confusing.

What I have done for some of my objects is implement Clone() like this:
<code>
public Object Clone()
{
BOLCustomerConfiguration newConfig =
(BOLCustomerConfiguration)this.MemberwiseClone();

// deep copy reference types
newConfig.m_dal = new DALMSAccess();
newConfig.m_description = (string)this.m_description.Clone();
newConfig.m_name = (string)this.m_name.Clone();
newConfig.m_deviceSettings = new BOLDeviceSettingsList();
foreach(BOLDeviceSettings item in this.m_deviceSettings)
{
newConfig.m_deviceSettings.Add( item );
}

return newConfig;
}
</code>

That seems correct to me and so far, it seems to behave correctly. String,
being an array and therefore a reference type needs a deep copy, correct?

Thanks again for the post,
Steve
 
No, string does not need a deep copy because string is a bit of an
oddity: it's immutable. That means that you can never change the
contents of a string, only generate a new string based on an existing
string. So, once you say:

string s = "Hello There!";
string a = s;

You can be guaranteed that the string that "a" refers to will always
say "Hello There!" unless you change "a". If you do this:

s = s.Substring(0, 5);

Then all you've done is assign "s" to refer to a different string that
contains "Hello". "a" will continue to refer to the original string,
which says "Hello There!".

So, yes, strings are reference types, but they are special reference
types that you can trust never to change.
 
Interesting, so for string, in my Clone() method I would simple need to do:
string newString = new string.empty();
newString = oldString;

Since there is not a constructor that will take string, I guess this is the
cleanest way?
 
Not even. All you need to do is this:

<code>
newConfig.m_description = this.m_description;
newConfig.m_name = this.m_name;
</code>

Since strings are immutable, you are guaranteed that the strings that
newConfig.m_description and newConfig.m_name refer to will never
change. The only way to "change them" is to point m_description and
m_name to some other strings.
 
Oh wow, this is pointing out a much bigger issue I'm having then ;)
I had weird behavior this morning where;
SettingsObject A.Name = "Default";
// create a copy of SettingsObject, B
B.Name = "Test";

was changing both values. I didn't check too into it, I just assumed they
were reference types and then changed the Clone() method, but based on your
post (and the test I just did), this would indicate that something very
different is happening (Like I didn't really create a copy of SettingsObject
but perhaps a reference)

OK, I'm done now, thanks for your help, I get it.
 
Back
Top