2009-01-11 23 views
18

¿Cuál sería la mejor manera de escribir una función de constructor de copia genérica para mis clases de C#? Todos heredan de una clase base abstracta, así que podría usar la reflexión para mapear las propiedades, pero me pregunto si hay una forma mejor.Genérico C# Copy Constructor

Respuesta

14

Puede crear una copia poco profunda eficientemente con reflexión mediante precompilación, por ejemplo con Expression. Por ejemplo, like so.

Para copias en profundidad, la serialización es el enfoque más confiable.

+0

+1 para las ideas claras en su ejemplo vinculado. – Ergwun

19

Evita la reflexión si puedes. Cada clase debe tener la responsabilidad de copiar sus propias propiedades y enviarlas al método base.

+0

tan sólo para aclarar, que sería mejor si tuviera un constructor de copia personalizada en cada clase que asigna explícitamente las propiedades? – lomaxx

+0

Lo haría. ¿Qué tan difícil es escribir? Ciertamente más fácil de leer a simple vista que un método basado en la reflexión. – duffymo

+0

Sí, recomendaría ese enfoque. –

23

Un constructor de copia básicamente significa que tiene un único parámetro, que es el objeto que va a copiar.

Además, haga una copia profunda, no una copia poco profunda.

Si usted no sabe lo que las copias son profundos y poco profundos, entonces éste es el trato:

Supongamos que está copiando una clase que tiene una sola fila de números enteros como campo.

Una copia superficial sería:

public class Myclass() 
{ 
    private int[] row; 
    public MyClass(MyClass class) 
    { 
     this.row = class.row 
    } 
} 

copia profunda es:

public class Myclass() 
{ 
    private int[] row; 
    public MyClass(MyClass class) 
    { 
     for(int i = 0; i<class.row.Length;i++) 
     { 
      this.row[i] = class.row[i]; 
     } 
    } 
} 

una copia profunda realmente obtiene los valores actuallos y los pone en un nuevo campo del nuevo objeto, mientras que una la copia superficial solo copia los punteros.

Con la copia superficial, si se establece:

row[3] = 5; 

y luego imprimir ambas filas, ambos grabados tendrán 5 como valor del cuarto número. Sin embargo, con una copia profunda, solo la primera impresión tendrá esto, ya que las filas no tienen los mismos punteros.

+0

Puede usar 'row.clone()' ya que C# permite clonar matrices primitivas. –

+4

¿No falla el código anterior debido a que 'row' nunca se inicializó? – AnotherParker

9

Aquí hay un constructor que estoy usando. Tenga en cuenta que este es un constructor superficial, y bastante simplista, debido a la naturaleza de mi clase base. Debería ser lo suficientemente bueno para comenzar.

public partial class LocationView : Location 
{ 
    public LocationView() {} 

    // base class copy constructor 
    public LocationView(Location value) { 
     Type t = typeof(Location); 
     PropertyInfo[] properties = t.GetProperties(); 
     foreach (PropertyInfo pi in properties) 
     { 
      pi.SetValue(this, pi.GetValue(value, null), null); 
     } 
    } 
    public Quote Quote { get; set; } 
} 
+0

One line-able: 'foreach (var propertyInfo en typeof (LocationView) .BaseType.GetProperties()) propertyInfo.SetValue (this, propertyInfo.GetValue (obj_to_copy_parameter, null), null);' también puede usar un inicializador de campo para solo leyó GetProperties una vez. –

+3

@ChrisMarisic Tiendo a evitar frases sueltas cuando sacrifica capacidad de lectura. – B2K

+0

Ver también http://stackoverflow.com/questions/14218989/best-way-to-clone-properties-of-disparate-objects Obtuve una extensión genérica para propiedades comunes de clonación superficial – B2K

0

Es posible hacer referencia a paquetes valueinjecter y NuGet fasterflect y uso:

public class Myclass() 
{ 
    private string _property; 
    public MyClass(MyClass obj) 
    { 
     this.InjectFrom(obj.DeepClone()); 
    } 
} 
Cuestiones relacionadas