Question

I've done some reading and cant seem to wrap my head around what the best approach would be to clone a List(of class) in my VB2010 project. I have three classes that are related like so

Public Class City
    'here are many fields of type string and integer
    Public Roads As New List(Of Road)
End Class
Public Class Road
    'here are many fields of type string and integer
    Public Hazards As New List(Of Hazard)
End Class
Public Class Hazard
    Implements ICloneable

    'here are many fields of type string and integer and double
    Public Function Clone() As Object Implements System.ICloneable.Clone
        Return Me.MemberwiseClone
    End Function
End Class

So lets say I have a city I'm working on, there are cases where I want to create, as a base one road and its hazards, then add another road but using the prior roads hazards as a starting point and then tweak the fields.

Dim rd As New Road
'add road fields

dim hz1 as New Hazard
'add hazard fields
dim hz2 as New Hazard
'add hazard fields

'add the hazard objects to the road
rd.Hazards.Add(hz1)
rd.Hazards.Add(hz2)

'add the road to the city
myCity.Roads.Add(rd)


'here I want to start a new road based on the old road
Dim rdNew As New Road

'copy or clone the hazards from old road
rdNew.Hazards = rd.Hazards '<============

'over-write some of the hazard fields
rdNew.Hazards(0).Description = "temp"

So I know that copying a class will copy the pointer and not the contents. I used the ICloneable interface in the hazard class but cant say I'm using it right. The Hazards variable is a list of Hazard class. How would i go about cloning that class?

Was it helpful?

Solution

Implementing IClonable doesn't mean that it replaces the regular assignment, it will still just copy the reference. And you aren't even copying the items, you are copying the list, which means that you still only have one list, but two references to it.

To use the Clone method you have to call it for each item in the list:

rdNew.Hazards = rd.Hazards.Select(Function(x) x.Clone()).Cast(Of Hazard).ToList()

OTHER TIPS

Imports System.IO
Imports System.Xml.Serialization        

 Public Function CopyList(Of T)(oldList As List(Of T)) As List(Of T)

            'Serialize
            Dim xmlString As String = ""
            Dim string_writer As New StringWriter
            Dim xml_serializer As New XmlSerializer(GetType(List(Of T)))
            xml_serializer.Serialize(string_writer, oldList)
            xmlString = string_writer.ToString()

            'Deserialize
            Dim string_reader As New StringReader(xmlString)
            Dim newList As List(Of T)
            newList = DirectCast(xml_serializer.Deserialize(string_reader), List(Of T))
            string_reader.Close()

            Return newList
        End Function

I know this is old.

rdNew.Hazards = rd.Hazards.ToList()

Even though it's already a list, ToList will create a new list based on it.

With VB 2019, this will create a shallow copy, but that's useful in some circumstances. That means that the list is new, but the elements of both rd.Hazards and rdNew.Hazards point to the same thing.

If you edit any particular hazard, the changes will be seen in both.

If you add a hazard to one list, the other list will not have it.

If you delete a hazard from one list, the other list will still have it.

If Hazard were a primitive type (like a string or integer), then editing items would not be reflected in the other list.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top