Cloning An Object

JDYoder

Centurion
Joined
Nov 18, 2003
Messages
144
I have an object I want to clone. I know the type, so I can declare my new object as the type I want, but then I want to loop through all the properties and assign them from the old variable to the new one. Is this possible?
 
Would
Code:
dim  otherobject as whatever

otherobject = new whatever
otherobject.randomproperty = 532
otherobject.what = "poo"

dim newobject as whatever

Newobject = otherobject
work?
 
Uh.. now you have two variables pointing to the same object, not an original plus a clone.

You either have to copy all the properties or even better use serialization. You can serialize to a memory stream and then de-serialize back to the new object.

The problem with copying all the properties is that:
1. It's tedious and must be modified when the properties change
2. You have to remember to do the copying from the class that the object is instantiated from - otherwise you'll miss the private fields that have no accessor (i.e., the hidden internal object state).
 
Wow, you're right, It doesn't work. I'm sorry, I'll test my ideas before posting them for now on.

So basically, you want a sub in the class that will do this?
Code:
Public Class whatever
    Public something As Integer
    Public what As String
    Public Sub clone(ByRef hmm As whatever) 'make sure it's byref.
        hmm = New whatever
        hmm.what = what 'set all the properties to eachother
        hmm.something = something
    End Sub
End Class
 
Here's a more maintainable way to do it:

1. just set the Serializable attribute on the class you want to copy
e.g.,
<Serializable()> _
Public Class ClassYouWantToCopy

2. place this general purpose routine somewhere (anywhere) and call it when you have a serializable class object you want a clone of:

Public Function CloneObject(ByVal oObject As Object) As Object
'returns a separate object with all serializable
'properties set to those of oObject (the object class
'must have the "Serializable" attribute)

Dim oStream As New System.IO.MemoryStream()
Dim oFormatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
oFormatter.Serialize(oStream, oObject)
oStream.Seek(0, IO.SeekOrigin.Begin)
Return oFormatter.Deserialize(oStream)
End Function

If you don't have control of the class for the object you want to clone (i.e., you can't set it to 'Serializable'), then you'll have to set each property one by one, but as I mentioned in the other reply, you can't guarantee a proper clone unless the clonable class is doing the copying (to include private fields).
 
Since objects change, and I don't want to have to remember to change my clone object by setting dozens of properties one by one, (and since I don't have access to the object's class) I was hoping VB.NET could do something like...

[o1 of class "whatever" already exists]

Dim i as integer
Dim o2 as new whatever
For i = 0 to whatever.properties.count - 1
o2(i).property = o1(i).property
next i

That way, I'd always get a perfect clone, regardless if the object changes down the road. FYI, I had someone write me this later in the day...


Use Reflection and GetProperties(). Here's the MS KB article and their code sample...

http://msdn.microsoft.com/library/d...ml/frlrfsystemtypeclassgetpropertiestopic.asp

I haven't played with it yet, but it looks promising. Pretty slick stuff if it works as I'm hoping, since I'd be able to make general "Clone code" that would work for any object. I can't play with it until Monday when I get back to work, but anyone's welcome to look at it sooner than I can and report your findings.

So is Serializing similiar to this or not? (I'm not familiar with the term and am unclear what it's all about.)
 
I think it comes down to this: if the classes in question come under your control (i.e., you can ensure they are serializable), then my approach is by far the easiest - the code I posted is all you need.

However, for objects of classes you can't be sure are serializable, then you need another approach.
 
IngisKahn said:
And be sure to use the ICloneable interface. Also have you checked out MemberwiseClone?

To your first statement, "Why is that?" And to your second one, no I haven't -- what is it?
 
ICloneable is a standard CLR interface which all classes that support cloning should implement. MemberwiseClone is a private member function of Object that does exactly what you're trying to do (i.e. perform a shallow copy). If an object doesn't implement ICloneable then it's probably not ment to be copied.
MSDN is your friend :)
 
This is an ancient thread but I was wondering something. Is there an explicit way for me to designate which way i use the '=' operator each time i use it?
in..
subject = predicate

It appears that '=' will make a copy of the predicate if the predicate and subject are simple properties or values.

I dont like that the same operator doesnt make copies when the subject and predicate are objects. Essentially it's just passing the predicate reference to the subject.

I'd just like a different operator for two very different operations. Let me know if one exists. Confusion could result with this operator, from what I see.

Lets say :
dim x as integer = 5
dim y as integer = 10
x = y
y = 20
Does x now equal 20? havent tested but I dont think so.

Or:
Button1.text = Button2.text
Button2.text = "Hello Sucker"
Does Button1.text = "Hello Sucker" now? havent tested but i dont think so.

I need to make an exact COPY of another button. The best thing i could do is use MemberwiseClone but it doesnt seem to be an option. I'll make a custom subroutine if I cant do it an easier way.
This does not work:
button1 = button2.MemberwiseClone
 
To answer your first question (the use of the = operator):

Of course, X will not = 20. You need to understand how assignment works with value types and reference types--the behavior of = is, in fact, already explicitly defined. If you look at it from the right prespective, they actually work the same way.

First, examine the way that normal (value-type) variable assignment works. When you say SomeVariable = SomeValue, you have a spot in memory referenced by SomeVariable and the value, SomeValue, is copied into that spot in memory. Let's look at a play-by-play:

Visual Basic:
'--------------------------X----Y
dim x as integer = 5    '  [U]5[/U]    0  The value of 5 is copied to x
dim y as integer = 10   '  5    [U]10[/U] The value of 10 is copied to y
x = y                   '  [U]10[/U]   10 The value of Y (10) is copied to x
y = 20                  '  10   [U]20[/U] The value is 20 is copied to Y (but not to X)

Now we look at reference types. If you have any experience at all with C# or ASM, you will be familiar with pointers. A pointer is just a 32-bit integer (in Win32) that references a memory location. Pointers are at the heart of .Net reference types. A variable that is declared as a reference type actually only stores a pointer. When you call a method or set a field or property, you tell the compiler "Perform this operation on the object stored at the memory location specified by my variable." For example, the code MyObject.SomeFunction() compiles down to "Call SomeFunction on the object that the pointer in MyObject points to."

The signifigance of that is that you must understand that reference-type variables are just pointers, internally represented exactly like an integer. So, when you assign an object to a variable, the reference (i.e. the pointer) is being assigned. Let's have a look.

Visual Basic:
'Class that holds a single value
Class SampleClass
    Public Value As Integer
  
    'Create instance with specified value
    Public Sub New(val As Integer)
        Value = val
    End Sub
End Class
 
'Now, let's examine how assignment works here.
'These memory locations are random, picked out of a hat, just to demonstrate.
Sub ShowAssignment()
    'MemoryLocation----------------X----------------Y---------------------
    'Value-----------------------------------X--------------Y-------------
    
    Dim X As New SampleClass(5)   '[U]123456[/U]    [U]5[/U]      0 (Nothing)
    Dim Y As New SampleClass(10)  '123456    5     [U]90210[/U]    [U]10[/U]
    X.Value = Y.Value             '123456    [U]10[/U]    90210    10
    Y.Value = 20                  '123456    10    90210    [U]20[/U]
 
    ' So far the values seem to be exactly the same as before.
 
    ' Here's where things get different:
    ' We will assign the pointer of Y to X
 
    X = Y                         '[U]90210     20[/U]    90210    20
 
    ' X now points to a different location in memory than before: the
    ' same location as Y. Now a change in Y will be reflected in X, and
    ' vice-versa
 
    X.Value = 100                 '90210     [U]100[/U]   90210    [U]100[/U]
 
    ' Notice that because X and Y point to the same memory, their value
    ' WILL ALWAYS be the same.
End Sub

The confusion comes from the fact that .Net does a real good job of hiding your pointers from you. If you get a good grasp on how pointers work, though, you will have a good understanding of how and why reference types behave the way they do.



To answer your question about making an exact copy of a button: This is not nearly as simple as it seems. If you create a member-by-member clone ("shallow copy") of a button you will run into problems, and fast. Button objects are full of pointers. If you create a member-by-member clone of a .Net Button object you will copy all the pointers instead of the data that the pointers reference (copying all the data that the pointers point to would be a "deep copy"). This means that you will have two objects that .Net thinks are separate buttons, but they will both reference the same Windows resources (i.e. Windows will think that they are the same button while .Net thinks they are different).

If you assign one Button variable to another it will just copy .Net's pointer, so both .Net and Windows will treat it as the same object.

If you want to create a duplicate of a Button you will have to write your own function to do so. It will have to create a new button and then copy all of the properties over.
 
Thanks MarbleEater, that was very informative. I really should hit a .Net textbook here one day and go over some basics.

I have actually used the '=' operator before for passing button Pointers and it's very useful. I wanted a lazy way to copy a button but it makes sense that would be slightly more difficult. So I made my own copy function that copies the properties that I think are important.

It would be nice to know exactly what are reference type pointers and what are not but I guess all data type instances will not be pointers. All other classes, objects, controls, will be pointers.
 
Back
Top