Help With ICloneable And Deep Copy

A

ags5406

Hi all. I'm trying to implement ICloneable with the intent of making
a completely new copy of the example class car below. I've read lots
of posts on this and other boards on the topic but I just can't quite
seem to get the code correct in the Clone function. I want a deep
copy so that in my example code, I can change the properties of NewCar
without affecting the properties of OldCar. All of my attempts end up
with a shallow copy where changing NewCar also changes OldCar. Not
sure what I'm doing wrong. Any help would be greatly appreciated.


Module Module1
Sub Main()

Dim OldCar As New Car

OldCar.TirePressure(0) = 11.0
OldCar.TirePressure(1) = 12.0
OldCar.TirePressure(2) = 13.0
OldCar.TirePressure(3) = 14.0
OldCar.Color = "Green"

Dim NewCar As Car = OldCar

NewCar.TirePressure(0) = 26.0
NewCar.TirePressure(1) = 27.0
NewCar.TirePressure(2) = 28.0
NewCar.TirePressure(3) = 29.0
NewCar.Color = "Blue"

Console.WriteLine("Old Car Tire Pressures: " & _
OldCar.TirePressure(0).ToString("0.0") & ", " & _
OldCar.TirePressure(1).ToString("0.0") & ", " & _
OldCar.TirePressure(2).ToString("0.0") & ", " & _
OldCar.TirePressure(3).ToString("0.0"))
Console.WriteLine("Old Car Color: " & OldCar.Color)

Console.WriteLine(vbCr)

Console.WriteLine("New Car Tire Pressures: " & _
NewCar.TirePressure(0).ToString("0.0") & ", " & _
NewCar.TirePressure(1).ToString("0.0") & ", " & _
NewCar.TirePressure(2).ToString("0.0") & ", " & _
NewCar.TirePressure(3).ToString("0.0"))
Console.WriteLine("New Car Color: " & NewCar.Color)

Console.WriteLine(vbCr)

Console.Write("Press any key to continue...")
Console.ReadLine()

End Sub
End Module

Class Car
Implements ICloneable

Public Function Clone() As Object Implements ICloneable.Clone
Dim oClone As New Car


'-----------------------------------------------------------------------------------------------------
'WHAT DO I PUT HERE EXACTLY????????????????????????

'-----------------------------------------------------------------------------------------------------

Return oClone
End Function

Private _TirePressure(3) As Single
Public Property TirePressure(ByVal Index As Integer) As Single
Get
Return _TirePressure(Index)
End Get
Set(ByVal value As Single)
_TirePressure(Index) = value
End Set
End Property

Private _Color As String
Public Property Color() As String
Get
Return _Color
End Get
Set(ByVal value As String)
_Color = value
End Set
End Property

End Class
 
L

Lloyd Sheen

ags5406 said:
Hi all. I'm trying to implement ICloneable with the intent of making
a completely new copy of the example class car below. I've read lots
of posts on this and other boards on the topic but I just can't quite
seem to get the code correct in the Clone function. I want a deep
copy so that in my example code, I can change the properties of NewCar
without affecting the properties of OldCar. All of my attempts end up
with a shallow copy where changing NewCar also changes OldCar. Not
sure what I'm doing wrong. Any help would be greatly appreciated.


Module Module1
Sub Main()

Dim OldCar As New Car

OldCar.TirePressure(0) = 11.0
OldCar.TirePressure(1) = 12.0
OldCar.TirePressure(2) = 13.0
OldCar.TirePressure(3) = 14.0
OldCar.Color = "Green"

Dim NewCar As Car = OldCar

NewCar.TirePressure(0) = 26.0
NewCar.TirePressure(1) = 27.0
NewCar.TirePressure(2) = 28.0
NewCar.TirePressure(3) = 29.0
NewCar.Color = "Blue"

Console.WriteLine("Old Car Tire Pressures: " & _
OldCar.TirePressure(0).ToString("0.0") & ", " & _
OldCar.TirePressure(1).ToString("0.0") & ", " & _
OldCar.TirePressure(2).ToString("0.0") & ", " & _
OldCar.TirePressure(3).ToString("0.0"))
Console.WriteLine("Old Car Color: " & OldCar.Color)

Console.WriteLine(vbCr)

Console.WriteLine("New Car Tire Pressures: " & _
NewCar.TirePressure(0).ToString("0.0") & ", " & _
NewCar.TirePressure(1).ToString("0.0") & ", " & _
NewCar.TirePressure(2).ToString("0.0") & ", " & _
NewCar.TirePressure(3).ToString("0.0"))
Console.WriteLine("New Car Color: " & NewCar.Color)

Console.WriteLine(vbCr)

Console.Write("Press any key to continue...")
Console.ReadLine()

End Sub
End Module

Class Car
Implements ICloneable

Public Function Clone() As Object Implements ICloneable.Clone
Dim oClone As New Car


'-----------------------------------------------------------------------------------------------------
'WHAT DO I PUT HERE EXACTLY????????????????????????

'-----------------------------------------------------------------------------------------------------

Return oClone
End Function

Private _TirePressure(3) As Single
Public Property TirePressure(ByVal Index As Integer) As Single
Get
Return _TirePressure(Index)
End Get
Set(ByVal value As Single)
_TirePressure(Index) = value
End Set
End Property

Private _Color As String
Public Property Color() As String
Get
Return _Color
End Get
Set(ByVal value As String)
_Color = value
End Set
End Property

End Class

Code for Clone function:

with oClone
.TirePressure = me.TirePressure
. Color = me.Color
end with
return oClone

All this is supposed to do is create a new object of the same type and
populate the properties. In your example this is trivial. For complex
objects the order of the property assignments might be important and certain
cases certain properties may not be cloned.

Hope this helps
LS
 
A

ags5406

Code for Clone function:

with oClone
    .TirePressure = me.TirePressure
    . Color = me.Color
end with
return oClone

All this is supposed to do is create a new object of the same type and
populate the properties.  In your example this is trivial.  For complex
objects the order of the property assignments might be important and certain
cases certain properties may not be cloned.

Hope this helps
LS

Thank you for trying. But this doesn't help. I included your
suggestion as follows:

Public Function Clone() As Object Implements ICloneable.Clone
Dim oClone As New Car

With oClone
.Color = Me.Color
For x As Integer = 0 To 3 Step 1
.TirePressure(x) = Me.TirePressure(x)
Next x
End With

Return oClone
End Function

Unfortunately, if I set NewCar.Color = "something" then it also
changes OldCar.Color = "something". I need NewCar to be a carbon copy
of OldCar when I create it, but I want to be able to change its
properties without affecting the properties of OldCar. I believe your
code suggestion results in a shallow clone whereas I need a deep
clone, if I have the terminology correct.
 
L

Lloyd Sheen

Code for Clone function:

with oClone
.TirePressure = me.TirePressure
. Color = me.Color
end with
return oClone

All this is supposed to do is create a new object of the same type and
populate the properties. In your example this is trivial. For complex
objects the order of the property assignments might be important and
certain
cases certain properties may not be cloned.

Hope this helps
LS

Thank you for trying. But this doesn't help. I included your
suggestion as follows:

Public Function Clone() As Object Implements ICloneable.Clone
Dim oClone As New Car

With oClone
.Color = Me.Color
For x As Integer = 0 To 3 Step 1
.TirePressure(x) = Me.TirePressure(x)
Next x
End With

Return oClone
End Function

Unfortunately, if I set NewCar.Color = "something" then it also
changes OldCar.Color = "something". I need NewCar to be a carbon copy
of OldCar when I create it, but I want to be able to change its
properties without affecting the properties of OldCar. I believe your
code suggestion results in a shallow clone whereas I need a deep
clone, if I have the terminology correct.


Dim NewCar As Car = OldCar
is your problem. If you have implemented ICloneable you want to use

Dim NewCar as Car = OldCar.Clone

all you are doing is creating a new reference to the old object. Clone it
and you get a copy of the object not a reference to the old one.

Hope this helps
LS
 
T

Tom Shelton

Hi all. I'm trying to implement ICloneable with the intent of making
a completely new copy of the example class car below. I've read lots
of posts on this and other boards on the topic but I just can't quite
seem to get the code correct in the Clone function. I want a deep
copy so that in my example code, I can change the properties of NewCar
without affecting the properties of OldCar. All of my attempts end up
with a shallow copy where changing NewCar also changes OldCar. Not
sure what I'm doing wrong. Any help would be greatly appreciated.
Class Car
Implements ICloneable

Public Function Clone() As Object Implements ICloneable.Clone
Dim oClone As New Car


'-----------------------------------------------------------------------------------------------------
'WHAT DO I PUT HERE EXACTLY????????????????????????

'-----------------------------------------------------------------------------------------------------

Return oClone
End Function

Making a deep copy of an object can range in difficulty from trivial to
complex - depending on the object and the members it contains. In your
particular case, the implementation is rather trivial:

Public Function Clone() As Object Implements IClonable.Clone
Dim oClone As New Car
oClone.Color = Me.Color
For i As Integer = 0 To Me._tirePressure.Length - 1
oClone.TirePressure(i) = Me._tirePressure(i)
Next i

Return oClone
End Function

Where things get interesting is if your object contains other objects, which
contain other objects, etc. It can get pretty cumbersome setting properties
and creating new objects :)

One shortcut, that can be used, provided that your object and all of it's
subobjects are marked serializable or implment ISerializable is to actually
serialize the object to a memory stream, and then deserialize it. That would
look something like:

Option Strict On
Option Explicit On

Imports System.Runtime.Serialization.Formatters.Binary
Imports System.IO

Module Module1

Sub Main()
Dim a As New Car()
a.Color = "Blue"

Dim b As Car = TryCast(a.Clone(), Car)
Console.WriteLine(b.Color)
End Sub

<Serializable()> _
Class Car
Implements ICloneable

Private _color As String
Private _tirePressure(3) As Single

Public Sub New()
_color = "Red"
For i = 0 To _tirePressure.Length - 1
_tirePressure(i) = 23.0
Next
End Sub

Public Property Color() As String
Get
Return _color
End Get
Set(ByVal value As String)
_color = value
End Set
End Property

Public Property TirePressure(ByVal index As Integer) As Single
Get
Console.WriteLine("returning value")
Return _tirePressure(index)
End Get
Set(ByVal value As Single)
Console.WriteLine("setting value")
_tirePressure(index) = value
End Set
End Property

' using a memory stream to clone an object
Public Function Clone() As Object Implements System.ICloneable.Clone
Dim bf As New BinaryFormatter()

Using ms As New MemoryStream()
bf.Serialize(ms, Me)
ms.Seek(0, SeekOrigin.Begin)
Return bf.Deserialize(ms)
End Using

End Function

End Class
End Module

Anyway, there is no one answer to this - because the implementation can depend
on the circumstances...
 
A

ags5406

Thank you for trying.  But this doesn't help.  I included your
suggestion as follows:

    Public Function Clone() As Object Implements ICloneable.Clone
        Dim oClone As New Car

        With oClone
            .Color = Me.Color
            For x As Integer = 0 To 3 Step 1
                .TirePressure(x) = Me.TirePressure(x)
            Next x
        End With

        Return oClone
    End Function

Unfortunately, if I set NewCar.Color = "something" then it also
changes OldCar.Color = "something".  I need NewCar to be a carbon copy
of OldCar when I create it, but I want to be able to change its
properties without affecting the properties of OldCar.  I believe your
code suggestion results in a shallow clone whereas I need a deep
clone, if I have the terminology correct.

Dim NewCar As Car = OldCar
 is your problem.  If you have implemented ICloneable you want to use

Dim NewCar as Car = OldCar.Clone

all you are doing is creating a new reference to the old object.  Cloneit
and you get a copy of the object not a reference to the old one.

Hope this helps
LS

Lloyd thank you very much. That solved my problem.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top