C#继承和向下转型继承层次结构

4

我想从一个已有的A类型的对象创建一个新的B类型的对象。B继承自A。我希望确保将A类型对象中的所有属性值都复制到B类型对象中。实现这一目标的最佳方法是什么?

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;
    }
}
3个回答

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) {

    }
}

编辑

如果你不想复制每个属性,你可以将A和B序列化,并将A的实例序列化(例如到一个流中,而不是文件),然后用它来初始化B的实例。但我要警告你,这种方法很糟糕,而且开销很大:

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;

您可以在这里获取有关ReadToEnd的更多信息。


感谢您添加序列化器代码。我可能还可以使用反射来循环遍历所有成员并复制值,但这也会带来很多开销。 - Iain Sproat

3
您可以为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;
   }

那么,您可以执行以下操作:
B myB = (B)myA;

这是代码的一个不错的重构 - 我喜欢B对A的转换负有责任。我还可以为B创建一个接受类型A对象的构造函数。不幸的是,它仍需要逐个移动每个属性的值。 - Iain Sproat
这可能会非常误导人...没有必要覆盖转换运算符... - bitxwise
我认为任何实现都需要将每个值复制过去,因为从一个类移动到其子类需要新的内存分配。我点了+1,但我也认为这可能会让其他开发人员难以理解。就我个人而言,我会提供一个重载的构造函数来接收基类。 - Rob

0

在面向对象的机制中,这是不可能的,但AutoMapper已经为此创建。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接