Deep Copy / Clone methods in the C # class hierarchy. Do I need an entire concrete implementation?

Let's say I have the following class hierarchy (including the base interface):

IAction -> (abstract) BaseAction -> (concrete) ImmediateAction -> (concrete) MovementAction 

Now let's say that IAction provides a method (well, really, a different interface that implements IAction, but let things simplify here!):

 // Returns a new IAction instance deep copied from the current instance. IAction DeepClone(); 

Ok so far? We have a deep copy method, and ImmediateAction has some properties that it wants to copy, so it will provide not only the DeepClone() implementation, but also a copy constructor:

 //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 has nothing inside of it that matters in DeepClone() at all, so it doesn't implement a copy method or constructor.

The problem I encountered is this:

 IAction x = new MovementAction(); IAction y = x.DeepClone(); //pleaseBeTrue is false bool pleaseBeTrue = y is MovementAction; 

Now I understand what is happening here - MovementAction does not implement DeepClone() , so ImmediateAction.DeepClone() is called instead, which creates a new ImmediateAction . Therefore, the type y in the above example is ImmediateAction instead of MovementAction .

So, after this long preamble, my question is: what is the best practice for this type of situation? I am stuck? I just had to implement the DeepClone() method no matter what for each class in the hierarchy? Is the pattern I use here wrong and is there a better way ?

One final note: I would like to avoid reflection, if at all possible.

+6
source share
3 answers

You can use the 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(); } } 
+2
source

So, you have two options:

  • Or implement DeepClone () every time and in detail (list of all non-common properties)
  • Or use "quick & dirty" but a shared implementation using reflection
+2
source

Usually you need to implement your clone method in specific classes. In fact, this code that you sent will not compile if ImmediateAction is abstract, as you said at the top:

 return new ImmediateAction(this); 
0
source

Source: https://habr.com/ru/post/928082/


All Articles