2

Firstly, I am aware of the similar question here: Assignment "=" operator in VB.NET 1.1

Suppose I have a VB.NET structure which contains an ArrayList:

 Structure MarbleCollection
    Private marbles As ArrayList
 End Structure

 Class Marble
    Public name As String
    Public radius As Double
 End Class

I want to understand what happens when I create two instances of MarbleCollection and assign one to the other using the "=" operator:

 marbleCol1 = marbleCol2

According to the accepted answer to the question linked above:

It's a reference copy, if the type is a reference type (ie: classes). If it's a value type (Structure), it will do a member by member copy.

When a member-by-member 'copy' is carried out (when assigning a value type), is VB.NET really just recursively calling the assignment operator on each of the members? If so, then assigning one MarbleCollection here to another will not produce a deep copy because the assignment operator between two marbles ArrayLists will produce a reference copy. I want a deep copy.

Is there a way that I can implicitly make a reference-type object copy itself like a value-type one? For example, I would find it useful to extend the functionality of the ArrayList class, but I don't want my subclass to copy its ArrayList values by reference, but instead value.

Take this concrete example:

 Class BookList
    Inherits ArrayList
 End Class

Is there something I can do to the BookList class (i.e. implement an interface) that will make it so that:

 books1 = books2

Will replicate the values inside books2 and assign the replicant references to books1?

I'm not looking to be spoon-fed the solution here and move on; I would appreciate an explanation of how the "=" operator actually functions and decides internally how it will carry out the assignment (and how I can influence it). Generalisation to other languages is welcome.

Edit:

There seems to be some confusion. I realize that it's not possible/advisable to overload the "=" operator. I want to understand how the operator works. I can then determine for myself how/if I can perform a deep copy by typing an assignment statement.

For instance, this may or may not be a correct, fully descriptive definition of the operator's behaviour:

  1. class1 = class2 - copies the reference of class2 to class1. They're the same instance.
  2. struct1 = struct2 - performs struct1.member = struct2.member for each member in struct2.
  3. primitive1 = primitive2 - creates a new primitive, replicates the value of primitive2 and writes the same value to the new primitive, and gives primitive1 the reference of this newly created primitive.

I'm looking for a definitive outline of behaviour as above.

Community
  • 1
  • 1
Myridium
  • 789
  • 10
  • 20
  • Have you looked into Deep Copying objects? – Dr Schizo Aug 04 '14 at 07:41
  • I know nothing about this. If I understand the meaning correctly, I do want to perform a deep copy, yes. I don't know how. – Myridium Aug 04 '14 at 07:43
  • You should implement a `DeepCopy` method on the structure to do the copy. You **shouldn't** try to do any **operator overload** as this would create an inconsistent behaviour to c# in general and will make debugging and maintenance harder than is needed. – Enigmativity Aug 04 '14 at 07:48
  • Surely there is some canonical way of altering the behaviour of the assignment operator? The point is that I want the behaviour of my class to be intuitive. I would prefer that **books1 = books2** perform a value-by-value replication. Is there a way to accomplish this? – Myridium Aug 04 '14 at 07:53
  • 1
    Perhaps this will be a useful read http://www.codeproject.com/Articles/36067/Shallow-and-Deep-Object-Copying. From the look of your question you seem to be very clued up as you have provided a very detailed question. You can implement ICloneable, an example of doing so can be found here http://www.java2s.com/Tutorial/VB/0160__Collections/DeepClone.htm. – Dr Schizo Aug 04 '14 at 07:54
  • @Myridium - Implementing `books1 = books2` to perform a deep copy would be **counter-intuitive** as it would go against the standard .NET behaviour and should be avoided. – Enigmativity Aug 04 '14 at 08:23
  • @Enigmativity Good point. However, for all the end-user knows, couldn't *BookList* be a *Struct* which performs a memberwise copy of value types? Or is there a fundamental difference? – Myridium Aug 04 '14 at 08:51
  • @Myridium - There is a fundamental difference - you expect all value types of members to make copies, but never reference type members. What you are proposing changes the behaviour of reference types member for the one situation only. – Enigmativity Aug 04 '14 at 12:04

1 Answers1

2

First of all - you can't override assignment operator = (Why aren't assignment operators overloadable in VB.NET?). If you assign structure to new structure, you copy just value fields, reference fields will stay the same (thus your new MarbleCollection.marbles will point to same object as original MarbleCollection.marbles). What you can do is implement your own method and call that method instead for deep clone.

Structure MarbleCollection
    Private marbles As ArrayList
    Public Function Clone() As MarbleCollection
        Dim result = New MarbleCollection()
        If marbles IsNot Nothing Then
            For Each m As Marble In marbles
                result.marbles.Add(m.Clone())
            Next
        End If
        Return result
    End Function
End Structure

Class Marble
    Public name As String
    Public radius As Double
    Public Function Clone() As Marble
        Return DirectCast(Me.MemberwiseClone(), Marble)
    End Function
End Class

If you're looking for automation of deep cloning, I usually perform binary serialization, then deserialization (which gives you deep clone); there are also libraries for that.

Point of interest - ICloneable interface.

Edit:

For automatic cloning via serialization, you can write your class like this:

(Shamelessly retaken from Deep cloning objects)

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

''' <summary>
''' Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
''' Provides a method for performing a deep copy of an object.
''' Binary Serialization is used to perform the copy.
''' </summary>
Public NotInheritable Class ObjectCopier
    Private Sub New()
    End Sub
    ''' <summary>
    ''' Perform a deep Copy of the object.
    ''' </summary>
    ''' <typeparam name="T">The type of object being copied.</typeparam>
    ''' <param name="source">The object instance to copy.</param>
    ''' <returns>The copied object.</returns>
    Public Shared Function Clone(Of T)(source As T) As T
        If Not GetType(T).IsSerializable Then
            Throw New ArgumentException("The type must be serializable.", "source")
        End If

        ' Don't serialize a null object, simply return the default for that object
        If [Object].ReferenceEquals(source, Nothing) Then
            Return Nothing
        End If

        Dim formatter As IFormatter = New BinaryFormatter()
        Dim stream As Stream = New MemoryStream()
        Using stream
            formatter.Serialize(stream, source)
            stream.Seek(0, SeekOrigin.Begin)
            Return DirectCast(formatter.Deserialize(stream), T)
        End Using
    End Function
End Class

Downside: it is a bit slower that MemberwiseClone() and all "deep cloneable" objects must be marked with <Serializable()> attribute.

Community
  • 1
  • 1
Ondrej Svejdar
  • 21,349
  • 5
  • 54
  • 89
  • Does the assignment operator internally use the *.Clone()* method of *IClonable* objects? If not, I don't see the purpose of using *IClonable* at all. Do you mind elaborating on the serialization route and the automation it provides? – Myridium Aug 04 '14 at 08:07
  • 2
    @Myridium No, it doesn't. Instead of `a = b`, you'd simply write `a = b.Clone()`. You can't override the assignment operator (and even if you could, you shouldn't). – Luaan Aug 04 '14 at 08:17
  • @Ondrej Svejdar It looks like the serialisation route is just another way to implement an explicit *Clone()* method. – Myridium Aug 04 '14 at 08:56
  • @Myridium - yes, but you don't have to write implementation of explicit Clone() yourself - as long as object is serializable. – Ondrej Svejdar Aug 04 '14 at 09:13
  • This answer is essentially correct, but I’d advise writing and using a copy constructor instead of a `Clone` method. `Clone` really only makes sense when you want polymorphic copying (via the `ICloneable` interface), and this is usually not an issue for value types anyway. – Konrad Rudolph Aug 04 '14 at 09:26