Implementing ICloneable
I was doing a little work on the Design Guidelines
document tonight and I noticed this section that we added recently.
I thought I'd post it here for your comments. Where are you
using ICloneable today? Do you agree with this suggestion?
1.1 Implementing
ICloneable
The ICloneable interface contains a single Clone method, which is
used to create a copy of the current object.
public interface ICloneable
{
object
Clone();
}
?
Do not implement
ICloneable
There are two general ways to implement ICloneable, either as a deep, or
non-deep copy. Deep-copy copies the cloned object and all objects referenced by
the object, recursively until all objects in the graph are copied. A non-deep
copy (referred to as ‘shallow’ if only the top level references are copied) may
do none, or part of a deep copy.
Because the interface
contract does not specify the type of clone performed, different classes have
different implementations. A consumer cannot rely on ICloneable to let
them know whether an object is deep-cloned or not.
Note : If you need a cloning
mechanism, define your own Clone, or Copy methodology, and ensure that you
document clearly whether it is a deep or shallow copy. An appropriate pattern
is:
public
<type> Copy();
?
Do not use
ICloneable in public APIs
Comments
Anonymous
April 09, 2003
Well, I need copy functionality for my objects, so I implement ICloneable. However I write applications, not libraries, so my decision doesn't affect anyone else.It seemed obvious to me that the definition was loose, so I would be wary about calling Clone on something I didn't author. If I used a third party class I would consult the documentation, and would expect their implementation not to change in a breaking way.I'm not sure that everybody inventing their own equivalent helps much.I experience a similar confusion over Equals, but maybe that's just me.Anonymous
April 09, 2003
Isn't (wasn't?) the point of ICloneable that the semantics are left to the type's author? You want a clone of my object - and I decide what being a clone is. Of course the problem with a weak contract is that given an arbitrary object reference, I can't discover the semantics of the implementation. The documentation doesn't help when you're discovering interfaces programmatically. IMO, It would be more helpful if there were two interfaces - one that implied shallow copies, and one that implied deep copies. In Eiffel, clone means shallow, and deep_clone is obvious.Anonymous
April 10, 2003
OK, forget the documentation! My problem with the author's decision is that I have cases where I really want a deep copy. I start with an object, create a copy, the user modify the copy, then I want to diff the two objects. So I want some interface to be deep_copy.I just find it frustrating that the only interface we have (although weak) is now considered a bad idea.Anonymous
April 10, 2003
David, this is a great note. And the idea of two separate interfaces (shallow/deep) to track this is still a possibility. The problem is that a single interface, for which we didn't define the contract resulted in disparate implementations. The 'ICloneable' nature of an object tells you nothing about what the Clone does, meaning that accepting an ICloneable object (unless you can guarantee you know the contract of each object) is all but useless. If I then take that object and call Clone on it, what do I get? I have no idea. Too many valid implementations, with different definitions of the contract have shipped for us to justify enforcing a guideline at this point.Consider that if you did implement ICloneable, expecting all implementations to be deep, then if someone passes you a collection (such as ArrayList) you're in trouble.Anonymous
April 10, 2003
I guess the only thing you can closely define is a deep copy. This should mean that my new object contains no references to the old one.As the guideline above points out, there are enless variations on a non-deep copy, so maybe a loose ICloneable would do for that. Then we need a new interface that is deep.Personally I think a clone that is anything other than shallow (i.e. a simple ref assignment) or deep (i.e. everything) is a nightmare. What use is a partial copy where the contained objects are copied or not based on the class author's choice?Anonymous
April 18, 2003
I agree with Nick. I'm for one like to make things specific. Wouldn't it be better, rather than just using documentation to state what a method does actually use a name that describes what it is doing? If it’s a deep copy have a method called deepcopy (or something similar), if it’s not then call the method it shallowcopy. Copy in my opinion can be to easily miss interpreted. If a method describes what it is doing the better as it leads to easier understanding of what a program is doing.Anonymous
August 05, 2003
It's a little too late to get rid of ICloneable now. It is implemented all over the Framework. I have used it once, to do a clone of every object in an array, but I could count on it only because I knew that every object was some primitive (int, double, etc). I always assumed the word "clone" meant "deep copy". This is what the convention has been in other languages and libraries.Anonymous
September 08, 2003
The docs for Object.MemberwiseClone say that you should use ICloneable if a shallow copy is not appropriate. To me that is saying that ICloneable should be a deep copy.Anonymous
July 06, 2007
As I've mentioned earlier, I have a long commute to and from work each day. Each day as I ride theAnonymous
October 20, 2008
Ho seguito il webcast " Disegno Architetturale: gli idiomi e le linee guida di desing per il .NET