基于父实例创建子类的实例?



请考虑以下类定义:

class A
{
public int Property1 { get; set; }
public int Property2 { get; set; }
}
class B : A // note that B is a subclass of A
{
// B has only one further property
public int OneMoreProperty { get; set; }
}

给定一个A的实例,我需要创建一个具有相同值的B实例。有没有比复制每个属性更好的方法呢?有机会利用BA的子类这一事实吗?这是我目前拥有的,在我看来非常不方便且容易出错:

// Create instance of A
A instanceA = new A();
instanceA.Property1 = 1;
instanceA.Property2 = 2;
// Create instance of B with same 
// values as the instance of A
B instanceB = new B();
instanceB.Property1 = instanceA.Property1;
instanceB.Property2 = instanceA.Property2;
instanceB.OneMoreProperty = 5;

正如@Jamiec所提到的,这里的继承关系可能通过组合更好地建模,但如果B语义上是一个A,一种方法是添加一个"复制构造函数":

class A
{
public int Property1 { get; set; }
public int Property2 { get; set; }
public A() { }
public A(A other)
{
Property1 = other.Property1;
Property2 = other.Property2;
}
}
class B : A
{
public int OneMoreProperty { get; set; }
public B() { }
public B(A other) : base(other) { }
}

然后,当您创建B实例时:

B instanceB = new B(instanceA);
instanceB.OneMoreProperty = 5;

您已经非常清楚地说明了为什么出于"重用"属性的目的进行继承通常是错误的选择。

继承意味着一种is-a关系,但你在这里建模的几乎可以肯定是A和B之间的has-a关系。因此,B应该只保存 A 的一个实例,而不需要将值从 A 复制到 B。

class A
{
public int Property1 { get; set; }
public int Property2 { get; set; }
}
class B 
{
public A A{ get; set; }
public int OneMoreProperty { get; set; }
}

然后

// Create instance of A
A instanceA = new A();
instanceA.Property1 = 1;
instanceA.Property2 = 2;
// Create instance of B with same 
// values as the instance of A
B instanceB = new B();
instanceB.A = instanceA;
instanceB.OneMoreProperty = 5;

这显然是过度简化的,你可能有一个需要A的构造函数,你可以引入接口,这样你就可以使AB以某种对你的领域有意义的共享方式运行。

您还应该考虑对象的不可变性,因为对上述示例中A实例的更改将影响B持有的引用。

我知道你到底是什么意思,有时有些类我们不能强制转换,因为多了一个属性。这可以使用反射来实现:

static Tout CopyProps<Tin, Tout>(Tin input) where Tout: Tin, new()
{
var result = new Tout();
foreach (var prop in typeof(Tin).GetProperties())
prop.SetValue(result, prop.GetValue(input));
return result;
}

用法是:

var a = new A{...}
var b = CopyProps<A,B>(a);

最新更新