IClonable

  • Thread starter Thread starter Zürcher See
  • Start date Start date
Z

Zürcher See

If I want to implement an IClonable interface, how can I copy the events
from my source object to the target "cloned" object?
 
If I want to implement an IClonable interface, how can I copy the events
from my source object to the target "cloned" object?


class CloneableWithEvents : ICloneable
{
public event MyDelegate MyEvent;

public object Clone()
{
CloneableWithEvents clone = new CloneableWithEvents();
clone.MyEvent += MyEvent;
return clone;
}
}



Mattias
 
Mattias Sjogren said:
class CloneableWithEvents : ICloneable
{
public event MyDelegate MyEvent;

public object Clone()
{
CloneableWithEvents clone = new CloneableWithEvents();
clone.MyEvent += MyEvent;
return clone;
}
}

wouldn't

CloneableWithEvents clone = (CloneableWithEvents)this.MemberwiseClone();

be simpler? It catches private fields, including events(assuming they are
normal fields, not in a hash table or anything, and it will work when
overridden, the above method breaks when you inherit from it.
 
Daniel,
wouldn't

CloneableWithEvents clone = (CloneableWithEvents)this.MemberwiseClone();

be simpler?

In this case, sure. But simpler isn't always better. :-) I didn't mean
to provide the definite way do handle this, just to show that it's
pretty straight forward and doesn't require any special magic.

It catches private fields, including events(assuming they are
normal fields, not in a hash table or anything, and it will work when
overridden,

MyEvent isn't virtual so you can't override it. ;-)

the above method breaks when you inherit from it.

If you expect your class to be inherited from (in code you don't
control) I would strongly suggest you avoid MemberwiseClone. You don't
know if the derived data can be safely be copied like that, or if it
for example references some unmanaged resource.



Mattias
 
thank's

Mattias Sjögren said:
class CloneableWithEvents : ICloneable
{
public event MyDelegate MyEvent;

public object Clone()
{
CloneableWithEvents clone = new CloneableWithEvents();
clone.MyEvent += MyEvent;
return clone;
}
}



Mattias
 
If you expect your class to be inherited from (in code you don't
control) I would strongly suggest you avoid MemberwiseClone. You don't
know if the derived data can be safely be copied like that, or if it
for example references some unmanaged resource.

You're missing the point of MemberwiseClone then.

The correct way to clone a base-class object is as follows:

public virtual object Clone()
{
//perform shallow copies of all members, even derived ones
MyClass clone = (MyClass)MemberwiseClone();

//perform deep copies where required
clone.deepCopyValue = (ContainedClass)deepCopyValue.Clone();

//I usually disconnect any events here, actually
//since I don't usually want event handlers cloned

//finally
return clone;
}


This way any sub-classes of MyClass will automatically get a correct clone
of the base class. If the derived classes need a deep copy of anything
else, they can override Clone as follows:

public override object Clone() {
//allow base class to do its work, and deep copy anything it needs to
MySubClass clone = (MySubClass)base.Clone();

//if any of the derived members need to be deep-copied, do that here:
clone.collection = new MyCollection(collection);

return clone;
}

It's up to each class to deep-copy any members that it needs. If the
sub-class fails to do so, it's the fault of the sub-class. At least with
the base-class using MemberwiseClone, sub-classes don't need to override
Clone unless they need to provide further deep-copying. Many times,
shallow-copies are perfectly acceptable.

If you don't use this method, you either need to provide a means for
sub-classes to safely clone all of the members of the base class (by making
them protected, perhaps), or through the use of
copy-constructor-like-semmantics (which then require all sub-classes to
follow a pattern which isn't very intuative to most C# programmers).

Using any other method (especially methods where Clone isn't marked virtual)
makes it the job of every derived class to ensure that the base class is
cloned properly.

Using the method I've described makes it the job of each class to deep-copy
only the members that it needs to. Sub-classes need not worry about how to
clone the parent class. This helps versioning as well---in case the parent
class introduces new members that require deep copies that the child class
is not aware of.

It seems to me that NOT using MemberwiseClone is more fragile than using it.
Or am I missing some obvious better way to implement cloning? I know
copy-constructors can work, but it's not nearly as elegant as a virtual
Clone implemented with MemberwiseClone and further deep copying.

--Matthew W. Jackson
 
Back
Top