2009-08-26 26 views
4

En venant d'un arrière-plan C++, je trouve que le clonage d'objets en C# est un peu difficile à faire. Pour clarifier une partie de ma confusion, je cherche une manière élégante de cloner un objet d'un type de base à un type dérivé.Clonage d'un type de référence C# vers un type de référence dérivé

À titre d'illustration:

public class Base 
{ 
    public string Member1; 
    public int Member2; 
    public float Member3; 
    public bool Member4; 
} 

public class Derived : Base 
{ 
    public List<Base> Children; 
} 

Base base = new Base(); 

Et que je veux créer une instance de « dérivé » tout en faisant une copie de l'objet membre à membre de base - de préférence sans les assigner manuellement.

Remarque: Peut-être que ce serait plus adapté à un type de valeur?

+0

Sons comme une chose étrange à faire, pour moi. Vous voulez fournir plus de contexte? – Noldorin

Répondre

4

Puisque vous ne pouvez pas changer le type d'un objet, vous avez quelques options:

  • encapsulentBase
  • utiliser un constructeur qui copie les valeurs de Base
  • copier les propriétés à partir de Base par réflexion ou similaire

Pour ce dernier, MiscUtil a un outil utile:

Base b= ... 
Derived item = PropertyCopy<Derived>.CopyFrom(b); 

pour l'encapsulation:

public class Derived 
{ 
    readonly Base b; 
    public Derived(Base b) {this.b=b;} 
    public List<Base> Children; 
    public string Member1 {get {return b.Member1;} set {...} } 
    public int Member2 {etc} 
    public float Member3 {etc} 
    public bool Member4 {etc} 
} 

Ou comme une copie manuelle:

public class Derived : Base 
{ 
    public Derived(Base b) { 
     this.Member1 = b.Member1; 
     // etc 
    } 
    // additional members... 
} 

ou (commentaires) obtenir la base de se copier:

public class Derived : Base 
{ 
    public Derived(Base b) : base(b) { } 
    // additional members... 
} 
public class Base 
{ 
    // members not shown... 
    public Base() {} 
    protected Base(Base b) { 
     this.Member1 = b.Member1; 
     // etc 
    } 
    // additional members... 
} 

(oùconstructeur deinitialise les champs de Base)

+0

Vous pouvez améliorer la version "copie manuelle" en utilisant des constructeurs de copie - de cette façon, vous pouvez demander 'Base' de créer une copie de lui-même, et il peut aussi jouer avec ses propres fichiers - si cela est nécessaire qu'une classe dérivée de celle-ci. –

+0

MiscUtil est exactement ce dont j'ai besoin, merci. – Ryall

2
/// Clone all fields from an instance of base class TSrc into derived class TDst 
public static TDst Clone<TSrc, TDst>(TSrc source, TDst target) 
    where TDst : TSrc 
{ 
    var bf = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; 
    foreach (FieldInfo fis in source.GetType().GetFields(bf)) 
     fis.SetValue(target, fis.GetValue(source)); 
    return target; 
} 

/// Create a new instance of a derived class, cloning all fields from type TSrc 
public static TDst Clone<TSrc, TDst>(TSrc source) 
    where TDst : TSrc, new() 
{ 
    return Clone(source, new TDst()); 
}