Search code examples
c#clonereference-type

Cloning a C# Reference Type to a Derived Reference Type


Coming from a C++ background, I am finding cloning of objects in C# a little hard to get used to. To clear up some of my confusion, I am looking for an elegant way to clone an object of a base type to a derived type.

To illustrate:

public class Base
{
    public string Member1;
    public int Member2;
    public float Member3;
    public bool Member4;
}

public class Derived : Base
{
    public List<Base> Children;
}

Base base = new Base();

And with that I want to create an instance of "Derived" whilst doing a memberwise copy of the Base object - preferably without assigning them manually.

Note: Maybe this would be more suited to a value type?


Solution

  • Since you can't change the type of an object, you have a few options:

    • encapsulate Base
    • use a constructor that copies the values from Base
    • copy the properties from Base through reflection or similar

    For the latter, MiscUtil has a helpful tool:

    Base b= ...
    Derived item = PropertyCopy<Derived>.CopyFrom(b);
    

    For encapsulation:

    public class Derived
    {
        readonly Base b;
        public Derived(Base b) {this.b=b;}
        public List<Base> Children;
        public string Member1 {get {return b.Member1;} set {...} }
        public int Member2 {etc}
        public float Member3 {etc}
        public bool Member4 {etc}
    }
    

    Or as a manual copy:

    public class Derived : Base
    {
        public Derived(Base b) {
            this.Member1 = b.Member1;
            // etc
        }
        // additional members...
    }
    

    or (comments) get the base to copy itself:

    public class Derived : Base
    {
        public Derived(Base b) : base(b) { }
        // additional members...
    }
    public class Base
    {
        // members not shown...
        public Base() {}
        protected Base(Base b) {
           this.Member1 = b.Member1;
            // etc
        }
        // additional members...
    }
    

    (where Base's constructor initializes the fields from Base)