26

Hi i want to cast the Parent object to Child object in C#

public class Parent
{
    public string FirstName {get; set;}
    public string LastName {get; set;}
    public string City {get; set;}
}

public class Child : Parent
{
    public string PhoneNumber {get; set;}
    public string MobileNumber {get; set;}
}

now the scenario is is a list of parent object and i want to generate list of child object so that i can have extended information

List<Parent> lstParent;
List<Child> lstChild = new List<Child>();

foreach(var obj in lstParent)
{
    lstChild.add((Child)obj);
}

as child class inherited parent class so the child class already have the parent class member i just want to fill them automatically so that i can populate datamember of child class

radbyx
  • 9,352
  • 21
  • 84
  • 127
Adnan Zameer
  • 732
  • 3
  • 10
  • 23

7 Answers7

32

I do so (this is just an example):

using System.Reflection;

public class DefaultObject
{
    ...
}

public class ExtendedObject : DefaultObject
{
    ....
    public DefaultObject Parent { get; set; }

    public ExtendedObject() {}
    public ExtendedObject(DefaultObject parent)
    {
        Parent = parent;

        foreach (PropertyInfo prop in parent.GetType().GetProperties())
            GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(parent, null), null);
    }
}

Using:

DefaultObject default = new DefaultObject { /* propery initialization */ };
ExtendedObject extended = new ExtendedObject(default); // now all properties of extended are initialized by values of default properties.
MessageBox.Show(extended.Parent.ToString()); // now you can get reference to parent object
ALT
  • 1,202
  • 11
  • 7
  • 2
    Why not simply `prop.SetValue(this, prop.GetValue(parent));`? – Andrew Apr 28 '17 at 08:12
  • @Andrew I've been digging for a while now and still can't find an answer as to why the former would be preferable. I'd love to know why if there's a genuine reason, so I can better understand this mechanism; at the moment I can't see how `prop` (a `PropertyInfo` element of the array returned by `parent.GetType().GetProperties()`) could *ever* be different than `GetType().GetProperty(prop.Name)` (the `PropertyInfo` looked up using `prop`'s `Name`), which really just leaves me confused as to why the verbose version is used here. – zcoop98 Sep 08 '21 at 23:27
  • Probably because Aleksey has been away for several years and never revised this answer. I guess he arrived to that working code after some effort and didn't realize it could be simplified. If my version works fine, I'd definitely go that way. – Andrew Sep 09 '21 at 01:39
25

If I understand your "I just want to fill them automatically" comment correctly, you want to create a new Child object that's populated with the values of the Parent, with default values for the new properties. Best way to do that is to create a constructor that copies the values:

public class Parent
{
   public string FirstName {get; set;}
    public string LastName {get; set;}
    public string City {get; set;}
}

public class Child : Parent
{
    public string PhoneNumber {get; set;}
    public string MobileNumber {get; set;}

    public Child (Parent parentToCopy)
    {
        this.FirstName = parentToCopy.FirstName;
        this.LastName = parentToCopy.LastName;
        this.City = parentToCopy.City;

        this.PhoneNumber = string.Empty; // Or any other default.
        this.MobileNumber = string.Empty;
    } 
}

Now you can use LINQ, like the answers above, to create a Child out of each Parent:

List<Child> lstChild = lstParent.Select(parent => new Child(parent)).ToList();

Note that this is very similar to @daryal's answer, but wraps the parent-to-child copying logic inside the constructor, rather than having it outside in the new Child() call.

Nilesh Thakkar
  • 2,877
  • 1
  • 24
  • 43
Avner Shahar-Kashtan
  • 14,492
  • 3
  • 37
  • 63
  • 9
    The drawback of this approach is maintenance. If you add a field in the parent, you must also be aware to insert the assignment in the constructor of the child. In this scenario this seems pretty simple. In a more complex environment this can and will be forgotten. That is why I prefer the approach with reflection. – Fabian Bigler Jun 08 '15 at 09:50
7

This is what I came up with form my solution.

    public static void ShallowConvert<T, U>(this T parent, U child)
    {
        foreach (PropertyInfo property in parent.GetType().GetProperties())
        {
            if (property.CanWrite)
            {
                property.SetValue(child, property.GetValue(parent, null), null);
            }
        }
    }
LawMan
  • 3,469
  • 1
  • 29
  • 32
6

I did like this:

class Parent
{
  ...
}

class Child :Parent
{
  ...
  public Child(Parent p)
  {
            foreach (FieldInfo prop in  p.GetType().GetFields())
                GetType().GetField(prop.Name).SetValue(this, prop.GetValue( p));

            foreach (PropertyInfo prop in  p.GetType().GetProperties())
                GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue( p, null), null);
  }
}
Mohsen Zahraee
  • 3,309
  • 5
  • 31
  • 45
3
var lstChild = lstParent.Cast<Child>().ToList();

or

var lstChild = lstParent.ConvertAll(x=>(Child)x);

Both of these, however, assume that the Parent list actually contains Child instances. You can't change the actual type of an object.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Hmmm... This is just a type-cast. Descendant-specific fields will be not initialized properly. You may end up with NullReferenceException hive. – Yury Schkatula Oct 27 '15 at 18:13
  • 1
    @YurySchkatula no, it will either fail with a type cast exception, or it will work fine; the OP asked for a cast; this **is a cast**. No initialization is required nor performed – Marc Gravell Oct 27 '15 at 18:30
2

You may use reflection as well, but this is simpler for your case.

foreach(var obj in lstParent)
{
    Child child = new Child(){ FirstName = obj.FirstName, LastName=obj.LastName, City = obj.City};
    child.MobileNumber = "some mobile number";
    child.PhoneNumber = "some phone number";
    lstChild.Add((Child)obj);
}
daryal
  • 14,643
  • 4
  • 38
  • 54
0

Another way to approach this solution is to have the Parent control the copy logic and Child will pass the copy source into the base constructor.

e.g. iterating on Avner's solution

public class Parent
{
    public string FirstName {get; set;}
    public string LastName {get; set;}
    public string City {get; set;}

    public Parent()
    {
    }

    public Parent(Parent copyFrom)
    {
        this.FirstName = copyFrom.FirstName;
        this.LastName = copyFrom.LastName;
        this.City = copyFrom.City;
    }
}

public class Child : Parent
{
    public string PhoneNumber {get; set;}
    public string MobileNumber {get; set;}

    public Child (Parent parentToCopy) : base(parentToCopy)
    {
    } 
}
Michael Johnston
  • 2,364
  • 2
  • 27
  • 48