cast the Parent object to Child object in C#
Asked Answered
D

7

28

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

Diggs answered 27/3, 2012 at 8:14 Comment(0)
C
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.

Cuttle answered 27/3, 2012 at 8:27 Comment(1)
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.Ceremony
F
33

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
Fidget answered 21/9, 2012 at 6:58 Comment(3)
Why not simply prop.SetValue(this, prop.GetValue(parent));?Fayre
@Fayre 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.Suffragette
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.Fayre
C
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.

Cuttle answered 27/3, 2012 at 8:27 Comment(1)
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.Ceremony
T
8

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);
            }
        }
    }
Takeoff answered 23/1, 2015 at 15:23 Comment(2)
Why not the other overloads, property.SetValue(child, prop.GetValue(parent));?Fayre
Best answer on here IMHO, plus @Andrew's helpful comment.Vail
C
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);
  }
}
Confluence answered 1/2, 2014 at 14:24 Comment(1)
Why not simply prop.SetValue(this, prop.GetValue(p));?Fayre
W
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.

Weary answered 27/3, 2012 at 8:17 Comment(2)
Hmmm... This is just a type-cast. Descendant-specific fields will be not initialized properly. You may end up with NullReferenceException hive.Siobhansion
@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 performedWeary
M
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);
}
Millham answered 27/3, 2012 at 8:19 Comment(0)
S
1

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)
    {
    } 
}
Spondaic answered 20/5, 2020 at 1:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.