C# inheritance. Derived class from Base class

22,989

Solution 1

The base problem you have is, that you have to construct an instance of type B (which contains of cause the properties of type A). Your approach to clone an A instance won't work, because that gives you an instance of type A, which you can't convert to B.

I would write constructors for class A and B which takes a parameter of type A. The constructor of class B just passes the value to its base class A. The constructor of class A knows how to copy the fields to itself:

class A {
    public A(A copyMe) {
        s1 = copyMe.s1;
        ...
    }

class B : A {

    public B(A aInstance) : base(aInstance) {
    }

}

Use it this way:

A a = new A();
a.s1 = "...";

B b = new B(a);

EDIT

When you don't want to have to change the constructor of A when adding new fields or props, you could use reflection to copy the properties. Either use a custom attribute to decorate what you want to copy, or copy just all props/fields of A:

public A (A copyMe) {
    Type t = copyMe.GetType();
    foreach (FieldInfo fieldInf in t.GetFields())
    {
        fieldInf.SetValue(this, fieldInf.GetValue(copyMe));
    }
    foreach (PropertyInfo propInf in t.GetProperties())
    {
        propInf.SetValue(this, propInf.GetValue(copyMe));
    }
}

I havn't tried the code, but the point should become clear.

Solution 2

You could create a generic clone method in class A:

     public T Clone<T>() where T : A, new() {
          return new T() { a = this.a, b = this.b};
     }

Or if you want to make the cloning extendable:

     public T Clone<T>() where T : A, new() {
          var result = new T();
          this.CopyTo(result);
          return result;
     }

     protected virtual void CopyTo(A other) {
          other.a = this.a;
          other.b = this.b;
     }

You use it like this:

     A  a = new A();
     // do stuff with a
     // Create a B based on A:
     B b = a.Clone<B>();

Please note: in your example, both the new A(), and the MemberwiseClone will create a new object of type A.

If you do not want to code the copy method yourself, you could look at a tool like AutoMapper.

Solution 3

After playing around and reading everything I could get my eyes on, both of the above solutions by GvS and Jan work. However, the end result that I wanted to achieve is not to be forced to write out each member in the Copy methods.

Why: a) If the class is edited and another object is added, the copy method will have to be updated. If someone else updates the class, they may forget to do this.

b) There may be a lot of members, and assigning them may be time consuming.

c) It just doesn't "feel" right. (Probably because I am very lazy).

Fortunately, I am not the only one with the same thoughts. Found a very very easy solution via the ValueInjector. (it has been discussed on these boards a lot).

After getting the dll (http://valueinjecter.codeplex.com/documentation)

The code becomes:

A a = new A();
a.s1 = "...";


B b = new B();
b.InjectFrom(a);

That's it :)

Obviously you would have to include:

using Omu.ValueInjecter;

And not forget to add it to the references.

Solution 4

You can also use a JSON serializer for example. You add a static method to your child-class which could then be called like this:

var porsche = Porsche.FromCar(basicCar);

Here, "Porsche" is the child class and "Car" is the base class. The function would then look something like this:

public class Porsche : Car
{
    public static Porsche FromCar(Car basicCar)
    {
        // Create a JSON string that represents the base class and its current values.
        var serializedCar = JsonConvert.SerializeObject(basicCar);

        // Deserialize that base class string into the child class.
        return JsonConvert.DeserializeObject<Porsche>(serializedCar);
    }

    // Other properties and functions of the class...
}

The trick here is, that properties that are available in the child but not the base, will be created with their default value, so null usually, depending on the type of the property. The deserialization also goes by the name of the property, so all properties are copied over.

I didn't test this code, but it should work, as I've done this once or twice before. Hope it helps someone.

Share:
22,989
Sam
Author by

Sam

Updated on January 10, 2020

Comments

  • Sam
    Sam over 4 years

    I have a base class

    public class A   
    {
        public string s1;
        public string s2;
    }
    

    I also have a derived class :

    public class B : A
    {
        public string s3;
    }
    

    Suppose my program created an instance of class A.

    A aClassInstance = new A();
    

    some parameters were set:

    aClassInstance.s1 = "string 1";
    aClassInstance.s2 = "string 2";
    

    At this point I would like to create an instance of class B. But I would like B to already have the values of my instance of class A.

    This DID NOT Work:

    public B bClassInstance = new B():
    bClassInstance = (B)aClassInstance;
    

    NEITHER DID THIS:

    Made a clone method within Class A.

    public B cloneA() {    
        A a = new A();
        a = (A)this.MemberwiseClone()
        return(B)a;
    }
    

    The VS code takes both of the above - but I get run-time errors

    Please help

  • Sam
    Sam over 12 years
    Thanks! In this example, would I have to set all of members (like a = this.a, b = this.b, etc.). If the class has multiple members, anyway to avoid coding each one? (if i decide to add another member, I would have to set it in the cloning function as well)
  • Sam
    Sam over 12 years
    I am trying to upgrade this so each member doesn't have to be copied individually:class A { public A(A copyMe) { s1 = copyMe.s1; the (A)copyMe.MemberwiseClone() should return a shallow clone of my call A that I need. Now all we need to do is pass it back to the B constructor... question is how. unfortunately we can't do this: Class A{ public A(A copyMe){ this = (A)copyMe.MemberwiseClone() } } ... }
  • user1149201
    user1149201 over 12 years
    You could build something with reflection (loop though all fields, and copy them), but from experience I know, you'd better control the copying yourself. Sometimes you need a shallow copy, for some objects you need a deep copy.
  • Jan
    Jan over 12 years
    @Sam: The problem is, that you have to construct an object of type B. Because A is part of B, you have to find a way of settings the properties of the new B instance, that belong to the type A. Your clone A approach won't workt because that gives you an instance of type A, where you need an instance of type B! What you can do, is to use reflection in the constructor of A. I will update my answer to reflect that.
  • PeterX
    PeterX about 9 years
    Why doesn't other = (A)this.MemberwiseClone(); work i nthe above (instead of having to set each property). I'm trying to avoid setting each property or use reflection.
  • Bill Tarbell
    Bill Tarbell over 5 years
    The reflection approach will throw if a property does not have a setter. Checking for propInf.CanWrite solves the problem