4

I'd like to create a new object of type B from an existing object of type A. B inherits from A. I'd like to ensure that all the property values in the object of type A are copied to the object of type B. What's the best method for achieving this?

class A
{
     public int Foo{get; set;}
     public int Bar{get; set;}
}

class B : A
{
    public int Hello{get; set;}
}


class MyApp{
    public A getA(){
         return new A(){ Foo = 1, Bar = 3 };
    }

    public B getB(){
         A myA = getA();
         B myB = myA as B; //invalid, but this would be a very easy way to copy over the property values!
         myB.Hello = 5;
         return myB;
    }

    public B getBAlternative(){
         A myA = getA();
         B myB = new B();

         //copy over myA's property values to myB
         //is there a better way of doing the below, as it could get very tiresome for large numbers of properties
         myB.Foo = myA.Foo;
         myB.Bar = myA.Bar;

         myB.Hello = 5;
         return myB;
    }
}
Iain Sproat
  • 5,210
  • 11
  • 48
  • 68

3 Answers3

4
class A {
    public int Foo { get; set; }
    public int Bar { get; set; }

    public A() { }

    public A(A a) {
        Foo = a.Foo;
        Bar = a.Bar;
    }
}

class B : A {
    public int Hello { get; set; }

    public B()
        : base() {

    }

    public B(A a)
        : base(a) {

    }
}

EDIT

If you don't want to copy each property, you can make A and B serializable and serialize your instance of A (say to a Stream, not a file) and initialize your instance of B with it. But I warn you, this is disgusting and has quite a bit of overhead:

A a = new A() {
    Bar = 1,
    Foo = 3
};

System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(A));
System.IO.Stream s = new System.IO.MemoryStream();
xs.Serialize(s, a);

string serial = System.Text.ASCIIEncoding.ASCII.GetString(ReadToEnd(s));
serial = serial.Replace("<A xmlns", "<B xmlns");
serial = serial.Replace("</A>", "</B>");

s.SetLength(0);
byte[] bytes = System.Text.ASCIIEncoding.ASCII.GetBytes(serial);
s.Write(bytes, 0, bytes.Length);
s.Position = 0;

xs = new System.Xml.Serialization.XmlSerializer(typeof(B));
B b = xs.Deserialize(s) as B;

You can get more information on ReadToEnd here.

Community
  • 1
  • 1
bitxwise
  • 3,534
  • 2
  • 17
  • 22
  • Thanks for adding the Serializer code. I'd probably also be able to use reflection to loop through all the members and copy the values across, but that also comes with a lot of overhead. – Iain Sproat Jan 27 '11 at 14:48
3

You could define an explicit casting operator for B:

   public static explicit operator B(A a) 
   {
     B b = new B();
     b.Foo = a.Foo;
     b.Bar = a.Bar;
     b.Hello = 5;
     return b;
   }

so then you can do:

B myB = (B)myA;
Nick Jones
  • 6,413
  • 2
  • 18
  • 18
  • This is a nice refactoring of the code - I like that B is then responsible for its casting from A. I could also create a constructor for B that accepted an object of type A. Unfortunately it still requires moving over the value for each property in turn. – Iain Sproat Jan 27 '11 at 11:38
  • That can be so misleading though...there's no need to override the casting operator... – bitxwise Jan 27 '11 at 11:38
  • I believe any implementation would require copying each value over, as moving from one class to it's subclass requires a new memory allocation. Gave a +1, but I also think that this could be difficult to follow for other developers. Personally I'd provide an overloaded constructor to take the base class. – Rob Jan 27 '11 at 11:39
0

This is not possible in an OO mechanism but AutoMapper has been created for this very usage.

Aliostad
  • 80,612
  • 21
  • 160
  • 208