Best way to create instance of child object from parent object

53,511

Solution 1

The base class needs to define a copy constructor:

public class MyObject
{
    protected MyObject(MyObject other)
    {
        this.Prop1=other.Prop1;
        this.Prop2=other.Prop2;
    }

    public object Prop1 { get; set; }
    public object Prop2 { get; set; }
}

public class MyObjectSearch : MyObject
{

    public double Distance { get; set; }

    public MyObjectSearch(MyObject obj)
         : base(obj)
    {
        this.Distance=0;
    }
    public MyObjectSearch(MyObjectSearch other)
         : base(other)
    {
        this.Distance=other.Distance;
    }
}

This way the setting of properties is handled for all derived classes by the base class.

Solution 2

You can use reflection to copy properties.

public class ChildClass : ParentClass
{


    public ChildClass(ParentClass ch)
    {
        foreach (var prop in ch.GetType().GetProperties())
        {
            this.GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(ch, null), null);
        }
    }
}

Solution 3

There is no easy way to do this, unfortunately. As you said, you would either have to use reflection, or create a "Clone" method that would generate a new child object using a parent object as input, like so:

public class MyObjectSearch : MyObject {

    // Other code

    public static MyObjectSearch CloneFromMyObject(MyObject obj)
    {
        var newObj = new MyObjectSearch();

        // Copy properties here
        obj.Prop1 = newObj.Prop1;

        return newObj;
    }
}

No matter what, you're either going to end up writing reflection code (which is slow), or writing each property out by hand. It all depends on whether or not you want maintainability (reflection) or speed (manual property copy).

Solution 4

A generic solution would be to serialize it to json and back. In the json-string is no information about the class name from which it was serialized. Most people do this in javascript.

As you see it works well for pocco objects but i don't guarantee that it works in every complex case. But it does event for not-inherited classes when the properties are matched.

using Newtonsoft.Json;

namespace CastParentToChild
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var p = new parent();
            p.a=111;
            var s = JsonConvert.SerializeObject(p);
            var c1 = JsonConvert.DeserializeObject<child1>(s);
            var c2 = JsonConvert.DeserializeObject<child2>(s);

            var foreigner = JsonConvert.DeserializeObject<NoFamily>(s);

            bool allWorks = p.a == c1.a && p.a == c2.a && p.a == foreigner.a;
            //Your code goes here
            Console.WriteLine("Is convertable: "+allWorks + c2.b);
        }
    }

    public class parent{
        public int a;
    }

    public class child1 : parent{
     public int b=12345;   
    }

    public class child2 : child1{
    }

    public class NoFamily{
        public int a;
        public int b = 99999;
    }

    // Is not Deserializeable because
    // Error 'NoFamily2' does not contain a definition for 'a' and no extension method 'a' accepting a first argument of type 'NoFamily2' could be found (are you missing a using directive or an assembly reference?)
    public class NoFamily2{
        public int b;
    }
}

Solution 5

If a shallow copy is enough, you can use the MemberwiseClone method.

Example:

MyObject shallowClone = (MyObject)original.MemberwiseClone();

If you need a deep copy, you can serialize/deserialize like this: https://stackoverflow.com/a/78612/1105687

An example (assuming you write an extension method as suggested in that answer, and you call it DeepClone)

MyObject deepClone = original.DeepClone();
Share:
53,511
Captain John
Author by

Captain John

UK Based software developer. Mainly working with .NET, Azure, Javascript and SQL

Updated on June 08, 2021

Comments

  • Captain John
    Captain John almost 3 years

    I'm creating a child object from a parent object. So the scenario is that I have an object and a child object which adds a distance property for scenarios where I want to search. I've chosen to use inheritance as my UI works equivalently with either a search object or a list of objects not the result of a location search. So in this case inheritance seems a sensible choice.

    As present I need to generate a new object MyObjectSearch from an instance of MyObject. At present I'm doing this in the constructor manually by setting properties one by one. I could use reflection but this would be slow. Is there a better way of achieving this kind of object enhancement?

    Hopefully my code below illustrates the scenario.

    public class MyObject {
    
        // Some properties and a location.
    }
    
    public class MyObjectSearch : MyObject {
    
        public double Distance { get; set; }
        
        public MyObjectSearch(MyObject obj) {
             base.Prop1 = obj.Prop1;
             base.Prop2 = obj.Prop2;
        }
    }
    

    And my search function:

    public List<MyObjectSearch> DoSearch(Location loc) { 
      var myObjectSearchList = new List<MyObjectSearch>();       
    
       foreach (var object in myObjectList) {
           var distance = getDistance();
           var myObjectSearch = new MyObjectSearch(object);
           myObjectSearch.Distance = distance;
           myObjectSearchList.add(myObjectSearch);
       } 
       return myObjectSearchList;
    }
    
  • Patrick Hofman
    Patrick Hofman over 10 years
    I think this is a good solution, since it is a better safeguard for passing all parameters then the copy or clone methods. When you really want to be sure, use reflection or similar solutions (like serializing properties from and to, but that might be too much)
  • John Alexiou
    John Alexiou over 10 years
    I do not see why have all the properties as arguments when a reference to the base class would suffice. You want MyObject to handle copying itself as good programming practices.
  • BartoszKP
    BartoszKP over 10 years
    @ja72 Just an example - such constructor is a typical general-purpose constructor. Depending on particular usage of the class, your solution or others proposed in other answers might be suitable.
  • Patrick Hofman
    Patrick Hofman over 10 years
    I agree with Bartosz. When implementing it like this, you cannot add a property in the constructor without an error in the parent class. This reminds you to add the field to the parent class.
  • rolivares
    rolivares about 10 years
    I think this is the best approach, there is no possibility to do this by cloning the source object. It's a really pain.
  • corentinaltepe
    corentinaltepe over 7 years
    This is very clean and fixes my issues with deep copy and inheritance.
  • CarComp
    CarComp about 5 years
    Sometimes google shows you what you really wanted to know, regardless of what you asked.
  • Nitin Sawant
    Nitin Sawant almost 2 years
    this is good way but need to write code for copying all the property values
  • John Alexiou
    John Alexiou almost 2 years
    @NitinS - yes you need to write code to do the copying per the requirements of the project. In some cases you need a shallow copy and others a deep copy. It is up to you, and this is what it is not automated. For an automatic solution look into record definitions which are classes that behave like struct.