2011-12-25 137 views
14

我有一个基类C#继承。从基类派生类

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代码采用上述两种的 - BU T I得到运行时错误

请帮

+2

克隆时要小心 - 特别是如果您的类具有可变引用类型的字段。决定是否需要深度克隆或浅层克隆,并将其记录下来。 – TrueWill 2011-12-25 22:39:14

+1

没错。这个特定的类没有引用,所以浅层的克隆就适用于它。我发现浅VS这里深克隆一个很好的职位有兴趣的人:http://itpksingh.blogspot.com/2009/08/shallow-copyingdeep-copyingobject.html – Sam 2011-12-26 00:22:32

+0

发现使用ValueInjector的解决方案。 StackOverFlow不允许我“回答我自己的问题”。一旦确定,将发布全部细节。 – Sam 2011-12-26 01:35:42

回答

21

您遇到的基本问题是,您必须构造一个类型为B(其中包含导致类型为A的属性)的实例。您的方法克隆A实例将不起作用,因为这会为您提供A类型的实例,您无法将其转换为B

我会写类A和B的构造函数,它需要一个类型为A的参数。类B的构造函数只是将值传递给它的基类A.A类的构造函数知道如何领域复制到其自身:

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

class B : A { 

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

} 

使用这种方式:

​​

编辑

当你不想有改变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)); 
    } 
} 

我没有带试过的代码,但问题应该变得清晰起来。

+0

我想升级它,以便每个成员不必单独复制:class A { public A(A copyMe){ s1 = copyMe.s1; (A)copyMe.MemberwiseClone()应返回我需要的我的调用A的浅度克隆。现在我们需要做的就是把它传回给B的构造函数......问题就是这样。 遗憾的是我们不能做到这一点: 类A { 公开发行A(A copyMe){ 此=(A)copyMe.MemberwiseClone() }} ... } – Sam 2011-12-26 00:47:08

+1

@Sam:问题是,您必须构造一个B类型的对象。因为A是B的一部分,所以您必须找到一种设置新B实例的属性的方法,它们属于A类型。您的* clone A *方法不会奏效,因为它给了你一个类型A的实例,你需要一个B类型的实例!你可以做的是在A的构造函数中使用反射。我将更新我的答案以反映这一点。 – Jan 2011-12-26 11:58:33

8

您可以创建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

+0

谢谢! 在这个例子中,我必须设置所有成员(如a = this.a,b = this.b等)。如果班级有多个成员,无论如何避免编码每个成员? (如果我决定添加另一个成员,我必须在克隆函数中设置它) – Sam 2011-12-26 00:21:23

+0

您可以使用反射来构建某些东西(循环遍历所有字段并复制它们),但根据我知道的经验,您最好控制自己的复制。有时你需要一个浅拷贝,对于一些需要深拷贝的对象。 – GvS 2011-12-26 08:39:19

+0

为什么不'other =(A)这个。MemberwiseClone();'在上面工作(而不必设置每个属性)。我试图避免设置每个属性或使用反射。 – PeterX 2015-03-03 00:20:52

1

玩耍和阅读的一切后,我可以通过GVS和Jan的工作让我的眼睛,上述两种解决方案。 但是,我想达到的最终结果不是强制写出Copy方法中的每个成员。

为什么: 一)如果该类编辑和添加另一个对象,复制方法将不得不进行更新。如果有人更新课程,他们可能会忘记这样做。

b)中可能有很多成员,并赋予它们可能是耗时的。

三)它只是没有“感觉”的权利。 (可能因为我很懒惰)。

幸运的是,我不是唯一一个有同样的想法。通过ValueInjector发现一个非常非常简单的解决方案。 (在这些板子上已经讨论过很多)。

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


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

就是这样:)

很明显,你必须包括:

得到DLL(http://valueinjecter.codeplex.com/documentation)

代码变得之后:

using Omu.ValueInjecter; 

不要忘记将它添加到引用。