Friday, October 15, 2010
Thoughts about (object) cloning
One commonly-useful method for objects to support is cloning. Unfortunately, cloning tends to pose many difficulties in object-oriented languages, since the type of object returned by the clone method will vary depending upon the type of object performing it, and since base types may be used to derive some types that allow cloning and some that do not.
As I see it, there are four types of classes when it comes to cloning:
Unfortunately, the .net framework really doesn't do much to indicate which types fall in which category. My proposed pattern would make things much clearer, and would look something like this:
For this example, the base class has one field which needs to be cloned, and the cloneable derived class adds another. Each cloneable derived class should declare a "Public Shadows Function Clone()" of its own type, which should call the overridable "CloneBase()" and typecast the result as appropriate. Each cloneable class which needs to do anything when cloned other than call its parent's cloning method should add an override to CloneBase, and that override should start by calling it's parent's CloneBase method.
Classes which aren't going to support cloning-related methods of their parents (e.g. MemberwiseClone in the case of SampleSemicloneableBase, or CloneBase in the case of NonCloneableDerived) should seal off those methods from protected classes; the implementation here is perhaps a little cutesy, but should be pretty good (Intellisense should set people straight if they try it).
Classes which follow my pattern can be readily classified into types #1, #3, and #4. Type #2 is a bit dodgy; classes which follow my pattern would not be type #2 (they'd be #3 even if all they do is call Object.MemberwiseClone) but there's no way of knowing whether a type which supports MemberwiseClone really supports it, or simply hasn't disabled it. But for types which follow the pattern, the cloning status would be readily apparent.
As I see it, there are four types of classes when it comes to cloning:
- Those that simply cannot be cloned
- Those that are perfectly happy if MemberwiseClone'd, but don't promise that their descendant classes will support cloning.
- Those that can be meaningfully cloned, but they require more than MemberwiseClone, and they don't promise that their descendants will support cloning.
- Those that can be cloned, and promise such ability on behalf of themselves and any descendant classes.
Unfortunately, the .net framework really doesn't do much to indicate which types fall in which category. My proposed pattern would make things much clearer, and would look something like this:
Class SampleSemicloneableBase
Enum DontTryThis
NoReallyDont = 0
End Enum
Public SampleArray1(0) As Integer
Protected Overridable Function CloneBase() As Object
Dim Result As SampleSemicloneableBase
Result = CType(MyBase.MemberwiseClone(), SampleSemicloneableBase)
Result.SampleArray1 = Result.SampleArray1.Clone
Return Result
End Function
Protected Shadows WriteOnly Property MemberwiseClone As DontTryThis
Set(ByVal value As DontTryThis)
Throw New NotSupportedException()
End Set
End Property
End Class
Class CloneableDerived
Inherits SampleSemicloneableBase
Public SampleArray2(0) As Integer
Public Shadows Function Clone() As CloneableDerived
Return CType(Me.CloneBase, CloneableDerived)
End Function
Protected Overrides Function CloneBase() As Object
Dim Result As CloneableDerived
Result = CType(MyBase.CloneBase(), CloneableDerived)
Result.SampleArray2 = Result.SampleArray2.Clone
Return Result
End Function
Public Overrides Function ToString() As String
Return SampleArray1(0).ToString & "." & SampleArray2(0).ToString
End Function
End Class
Class NonCloneableDerived
Inherits SampleSemicloneableBase
Protected Shadows WriteOnly Property CloneBase As DontTryThis
Set(ByVal value As DontTryThis)
Throw New NotSupportedException()
End Set
End Property
End Class
Class cloningTest
Shared Sub test()
Dim thing1 As New CloneableDerived
thing1.SampleArray1(0) = 1
thing1.SampleArray2(0) = 2
Dim thing2 As CloneableDerived = thing1.Clone
Debug.Print(thing1.ToString & "/" & thing2.ToString)
thing2.SampleArray1(0) = 3
thing2.SampleArray2(0) = 4
Debug.Print(thing1.ToString & "/" & thing2.ToString)
End Sub
End Class
For this example, the base class has one field which needs to be cloned, and the cloneable derived class adds another. Each cloneable derived class should declare a "Public Shadows Function Clone()" of its own type, which should call the overridable "CloneBase()" and typecast the result as appropriate. Each cloneable class which needs to do anything when cloned other than call its parent's cloning method should add an override to CloneBase, and that override should start by calling it's parent's CloneBase method.
Classes which aren't going to support cloning-related methods of their parents (e.g. MemberwiseClone in the case of SampleSemicloneableBase, or CloneBase in the case of NonCloneableDerived) should seal off those methods from protected classes; the implementation here is perhaps a little cutesy, but should be pretty good (Intellisense should set people straight if they try it).
Classes which follow my pattern can be readily classified into types #1, #3, and #4. Type #2 is a bit dodgy; classes which follow my pattern would not be type #2 (they'd be #3 even if all they do is call Object.MemberwiseClone) but there's no way of knowing whether a type which supports MemberwiseClone really supports it, or simply hasn't disabled it. But for types which follow the pattern, the cloning status would be readily apparent.
Comments:
<< Home
Hey! :)
We just launched Morris bookoo - it's a massive online yard sale for Morris and surrounding areas.- Thousands of people buying and selling used stuff from each other, in a fun, family-friendly way! :)
We're getting the word out to some local bloggers, and would like to send you a free bookoo t-shirt (no strings attached!). If you would like a free t-shirt, will you send me an email at kellin@bookoo.com with your address and shirt size? I'll get it out to you right away!
Check out the website:
http://morris.bookoo.com/
Thanks!
Post a Comment
We just launched Morris bookoo - it's a massive online yard sale for Morris and surrounding areas.- Thousands of people buying and selling used stuff from each other, in a fun, family-friendly way! :)
We're getting the word out to some local bloggers, and would like to send you a free bookoo t-shirt (no strings attached!). If you would like a free t-shirt, will you send me an email at kellin@bookoo.com with your address and shirt size? I'll get it out to you right away!
Check out the website:
http://morris.bookoo.com/
Thanks!
<< Home