2012-02-10 18 views
14

Suponiendo que tengo un Objeto ItemVO en el que hay un montón de propiedades ya asignadas. por ejemplo:Duplicar objeto y trabajar con duplicado sin cambiar original

ItemVO originalItemVO = new ItemVO(); 
originalItemVO.ItemId = 1; 
originalItemVO.ItemCategory = "ORIGINAL"; 

me gustaría crear otro duplicado mediante el uso de:

duplicateItemVO = originalItemVO; 

y luego usar el duplicateItemVO y alterar sus propiedades, sin cambiar la originalItemVO:

// This also change the originalItemVO.ItemCategory which I do not want. 
duplicateItemVO.ItemCategory = "DUPLICATE" 

¿Cómo puedo lograr esto, sin cambiar la clase ItemVO?

Gracias

public class ItemVO  
{ 
    public ItemVO() 
    { 
     ItemId = ""; 
     ItemCategory = ""; 
    } 

    public string ItemId { get; set; } 
    public string ItemCategory { get; set; } 
} 
+3

duplicado posible: http://stackoverflow.com/questions/78536/cloning-objects-in-c-sharp – Kekoa

Respuesta

10

Usted tendría que construir una nueva instancia de la clase, no sólo asignar la variable:

duplicateItemVO = new ItemVO 
    { 
     ItemId = originalItemVO.ItemId, 
     ItemCategory = originalItemVO.ItemCategory 
    }; 

Cuando estás tratando con tipos de referencia (de cualquier clase), solo asignar una variable es crear una copia de la referencia al objeto original. Como tal, establecer valores de propiedad dentro de ese objeto también cambiará el original. Para evitar esto, necesitas construir una nueva instancia de objeto.

+0

¿Hay otra manera en lugar de asignar explícitamente cada propiedad en originalItemVO a duplicateItemVO ? He usado un itemVO con 2 propiedades por simplicidad ... pero tengo alrededor de 30+ – Gotcha

+2

@Gotcha Cree un constructor en su clase que funcione desde una segunda instancia, e internamente haga la configuración apropiadamente. Ese es el método más fácil de mantener, entonces simplemente escribirías: 'duplicateItemVO = new ItemVO (originalItemVO);' –

1

clase son reference type y cuando cambia una instancia, cambiará la referencia original. a fin de utilizar value type objeto para superar su tarea (por ejemplo: utilizar struct en lugar de la clase)

public struct ItemVO { *** } 

o se puede poner en práctica ICloneable Interface para su clase

+0

Bien, he pensado esto ... Preferiría no cambiar esta clase a una estructura para evitar otro impacto de este cambio Solo estoy trabajando en una pequeña porción del código que tiene esta clase existente ... que no puedo modificar. ¿De qué otra manera podría lograr esto? – Gotcha

+0

puede implementar [ICloneable Interface] (http://msdn.microsoft.com/en-us/library/system.icloneable.aspx) para su clase –

6

Con el fin de cambiar una instancia sin cambiar la otra necesita clonar los valores reales de esta instancia y no la referencia. El patrón utilizado en .Net es implementar ICloneable. Así su código se vería así:

public class ItemVO: ICloneable 
    { 
    public ItemVO() 
    { 
     ItemId = ""; 
     ItemCategory = ""; 
    } 

    public string ItemId { get; set; } 
    public string ItemCategory { get; set; } 

    public object Clone() 
    { 
     return new ItemVO 
     { 
      ItemId = this.ItemId, 
      ItemCategory = this.ItemCategory 
     }; 
    } 
} 

Ahora note que necesita una conversión explícita al usar Clone() (o usted puede hacer su propio que devuelve ItemVO).

duplicateItemVO = (ItemVO) originalItemVO.Clone(); 
+0

Esto tiene sentido, pero suponiendo que no puedo cambiar la clase ItemVO, ¿cómo puede hacerlo? Lo logro? – Gotcha

+1

En este caso, tiene una de dos opciones: (1) extender la clase y luego implementar IColneable desde la clase secundaria. (2) tiene que volver a crear el objeto manualmente cada vez que necesita asignarlo, para crear el objeto manualmente solo usa el mismo código en el método Clonar. Prefiero la primera opción, especialmente si terminas haciendo esto en muchos lugares. –

0

Por defecto los objetos son de tipo de referencia.

Asignar un objeto a otro objeto significa que solo se refiere a la dirección del objeto. Cualquier cambio en cualquier objeto se reflejará en ambos.

Para resolver este problema, debe haber inicializado el objeto usando la palabra clave "nueva", luego agregue este valor del objeto en el primer objeto.

6

No se puede copiar prácticamente un objeto ya que es más probable que sea de tipos de referencia. El método ideal es serializar el objeto en uno nuevo - Siempre que su clase sea serializable (proporcionando el atributo [Serializable] en la declaración de clase).

private static T Clone<T>(T source) 
    { 
     if (!typeof(T).IsSerializable) 
     { 
      throw new ArgumentException("The type must be serializable.", "source"); 
     } 

     if (Object.ReferenceEquals(source, null)) 
     { 
      return default(T); 
     } 

     System.Runtime.Serialization.IFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 
     Stream stream = new MemoryStream(); 
     using (stream) 
     { 
      formatter.Serialize(stream, source); 
      stream.Seek(0, SeekOrigin.Begin); 
      return (T)formatter.Deserialize(stream); 
     } 
    } 

Ahora puede utilizar este código:

[Serializable] 
public class MyClass 
{ 
    public int a {get; set;} 
    public int b {get; set;} 
}  
var obj = new MyClass{ 
a = 10, 
b = 20, 
}; 

var newobj = Clone<MyClass>(obj); 

obtendrá una copia completamente nueva de obj. Nota: Cualquier otra clase dentro de MyClass también debe declararse con el atributo [Serializable].

+0

¡Gracias por este tidbit útil! ¿Has comprobado el rendimiento de esto en un objeto grande? – callisto

+0

Sí, @callisto, lo he probado en objetos grandes y, siempre que haya suficiente memoria disponible, funciona. –

+0

¡Gracias! Usar por completo está funcionando sin dañar mi código, –

0

A partir de C# 4.5, el objeto de la clase base contiene un método llamado MemberwiseClone que le permite realizar una copia superficial de ese objeto y devolver el resultado como una nueva instancia. (Si un campo es un tipo de valor, se realiza una copia bit por bit del campo. Si un campo es un tipo de referencia, la referencia se copia pero el objeto referido no lo es, por lo tanto, el objeto original y su clon se refieren para el mismo objeto.)

Esto es útil si está buscando implementar un patrón de diseño de prototipo.

Si usted está buscando para poner en práctica una copia profunda (todo dentro de la clase se duplica como nuevas instancias) a continuación, la serialización o la reflexión son probablemente las mejores herramientas

0

sugiere emplear como tal en el siguiente enlace. Para mí funcionó muy bien.

https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone(v=vs.110).aspx

public Person ShallowCopy() 
{ 
    return (Person) this.MemberwiseClone(); 
} 
+0

Si bien este enlace puede responder a la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace de referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página vinculada cambia. - [De la opinión] (/ reseña/mensajes de baja calidad/17233687) –

Cuestiones relacionadas