我有一个基类
public class A
{
public string s1;
public string s2;
}
我还有一个派生类:
public class B : A
{
public string s3;
}
假设我的程序创建了一个A类实例。
A aClassInstance = new A();
设置了一些参数:
aClassInstance.s1 = "string 1";
aClassInstance.s2 = "string 2";
此时我想创建一个B类实例。但是我希望B已经拥有了我的A类实例的值。
这不行::
public B bClassInstance = new B():
bClassInstance = (B)aClassInstance;
没有这样:
在A类中制作克隆方法。
public B cloneA() {
A a = new A();
a = (A)this.MemberwiseClone()
return(B)a;
}
VS代码采用上述两种方法 - 但我得到了运行时错误
请帮忙
答案 0 :(得分:28)
您遇到的基本问题是,您必须构造一个类型为B
的实例(其中包含类型为A
的属性)。克隆A
实例的方法不起作用,因为它为您提供了A
类型的实例,您无法将其转换为B
。
我会为类A和B编写构造函数,它接受类型A的参数。类B的构造函数只是将值传递给它的基类A.类A的构造函数知道如何将字段复制到自身:< / p>
class A {
public A(A copyMe) {
s1 = copyMe.s1;
...
}
class B : A {
public B(A aInstance) : base(aInstance) {
}
}
以这种方式使用:
A a = new A();
a.s1 = "...";
B b = new B(a);
修改强>
如果您不想在添加新字段或道具时更改A
的构造函数,则可以使用反射来复制属性。使用自定义属性来装饰要复制的内容,或者只复制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));
}
}
我没有尝试过代码,但重点应该是明确的。
答案 1 :(得分:9)
您可以在A类中创建通用克隆方法:
public T Clone<T>() where T : A, new() {
return new T() { a = this.a, b = this.b};
}
或者,如果您想使克隆可扩展:
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;
}
你这样使用它:
A a = new A();
// do stuff with a
// Create a B based on A:
B b = a.Clone<B>();
请注意:在您的示例中,新的A()和MemberwiseClone都将创建A类型的新对象。
如果您不想自己编写复制方法,可以查看AutoMapper之类的工具。
答案 2 :(得分:2)
在玩完并阅读我可以看到的所有内容之后,GvS和Jan的上述两种解决方案都得到了解决。 但是,我想要实现的最终结果不是强制在Copy方法中写出每个成员。
为什么: a)如果编辑了类并添加了另一个对象,则必须更新复制方法。如果其他人更新了课程,他们可能会忘记这样做。
b)可能会有很多成员,分配这些成员可能会非常耗时。
c)它没有“感觉”正确。 (可能是因为我非常懒惰)。
幸运的是,我不是唯一有同样想法的人。通过ValueInjector找到了一个非常简单的解决方案。 (已经在这些板上进行了很多讨论)。
获取dll后(http://valueinjecter.codeplex.com/documentation)
代码变为:
A a = new A();
a.s1 = "...";
B b = new B();
b.InjectFrom(a);
就是这样:))
显然你必须包括:
using Omu.ValueInjecter;
不要忘记将其添加到参考文献中。
答案 3 :(得分:1)
例如,您还可以使用JSON序列化器。您将一个静态方法添加到您的子类中,然后可以这样调用它:
var porsche = Porsche.FromCar(basicCar);
在这里,“保时捷”是孩子类,“汽车”是基类。该函数将如下所示:
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...
}
这里的窍门是,将使用默认值创建子级中可用但子级中不可用的属性,因此通常为null,具体取决于属性的类型。反序列化也使用属性的名称,因此将所有属性复制过来。
我没有测试此代码,但它应该工作,因为我之前已经做过一两次。希望对别人有帮助。