Let's say I have the following class hierarchy (base interface included):
IAction -> (abstract) BaseAction -> (concrete) ImmediateAction -> (concrete) MovementAction
Now, let's say IAction exposes a method (well, really a different interface that IAction implements does but let's keep things simple here!):
// Returns a new IAction instance deep copied from the current instance.
IAction DeepClone();
Good so far? We have our deep copy method, and ImmediateAction
has some properties that it wants copied so it will provide not only an implementation of DeepClone()
, but a copy constructor as well:
//Base Action implementation
protected BaseAction(BaseAction old)
{
this.something = old.something;
}
//Immediate Action Implementation
protected ImmediateAction(ImmediateAction old)
: base(old)
{
this.anything = old.anything;
}
public IAction DeepClone()
{
return new ImmediateAction(this);
}
Now, let's say MovementAction
doesn't have anything inside of it that's relevant in a DeepClone()
at all, so it doesn't implement the method or a copy constructor.
The problem that I'm having is this:
IAction x = new MovementAction();
IAction y = x.DeepClone();
//pleaseBeTrue is false
bool pleaseBeTrue = y is MovementAction;
Now, I understand what's going on here - MovementAction
does not implement DeepClone()
, so ImmediateAction.DeepClone()
is called instead, which instantiates a new ImmediateAction
. Hence, the type of y
in the above example is ImmediateAction
instead of MovementAction
.
So, after this lengthy preamble, my question is this: what is the best practice for this type of situation? Am I stuck? Do I simply have to implement a DeepClone()
method no matter what for every class along the hierarchy? Is the pattern that I am using here incorrect, and there's a better way?
One final note: I would like to avoid reflection if at all possible.
A deep copy, in contrast, means that you copy an entire object (struct). If it has members that can be copied shallow or deep, you also make a deep copy of them.
It means first constructing a new collection object and then recursively populating it with copies of the child objects found in the original. In the case of deep copy, a copy of the object is copied into another object. It means that any changes made to a copy of the object do not reflect in the original object.
Could use an extension method and do incremental cloning
public static class DeepCopyExt
{
public static T DeepCopy<T>(this T item)
where T : ThingBase, new()
{
var newThing = new T();
item.CopyInto(newThing);
return newThing;
}
}
public abstract class ThingBase
{
public int A { get; set; }
public virtual void CopyInto(ThingBase target)
{
target.A = A;
}
}
public class ThingA : ThingBase
{
}
public class ThingB : ThingA
{
public int B { get; set; }
public override void CopyInto(ThingBase target)
{
var thingB = target as ThingB;
if(thingB == null)
{
throw new ArgumentException("target is not a ThingB");
}
thingB.B = B;
base.CopyInto(thingB);
}
}
class Program
{
static void Main(string[] args)
{
var b = new ThingB
{
A = 1,
B = 3
};
//c is ThingB
var c = b.DeepCopy();
var b1 = new ThingA
{
A = 1,
};
//c1 is ThingA
var c1 = b1.DeepCopy();
Debugger.Break();
}
}
So yes, you have two options:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With