2009-03-10 17 views
5

Creé una clase llamada Colors. Estoy configurando ciertas propiedades en el objeto Colors y configurándolo en una variable Session. Cuando accedo a la variable Session en otra página, me doy cuenta de que si cambio propiedades en objColors a continuación, cambia la sesión y no conserva las propiedades originales, que es lo que quiero que haga. Aquí hay un ejemplo:¿Cómo se hace una copia de un objeto?

Session["Colors"] = Colors; 

Colors objColors = Session["Colors"]; 

//If I change objColors, it changes the Session. I don't want this to happen. 

¿Existe alguna forma mejor de conservar las propiedades originales? ¿Por qué hace esto?

Respuesta

7

Cree un constructor de copia para Colors. Entonces, haz esto.

Colors objColors = new Colors((Colors)Session["Colors"]); 

En su nuevo constructor, simplemente copie los valores que necesita y haga las otras cosas relacionadas con el constructor.

lo que está sucediendo en su código es que vas a encontrar un puntero a unos colores de los objetos. Session ["Colors"] y objColors apuntan al mismo objeto en la memoria, por lo que cuando modifica uno, los cambios se reflejan en ambos. Desea un nuevo objeto Colors de la marca Spankin, con valores inicializados de objColors o Session ["Colors"].

edición: Un constructor de copia podría tener este aspecto:

public Colors(Colors otherColors) 
{ 
    this.privateVar1 = otherColors.privateVar1; 
    this.publicVar2 = otherColors.publicVar2; 
    this.Init(); 
} 
+0

¿Puede ser más específico sobre cómo crear un constructor de copia? – Xaisoft

+0

@ Xaisoft es su trabajo crear la lógica para copiar. Se trata de tomar cada valor del objeto antiguo y aplicarlo al nuevo. –

3

Puede aplicar sus propios métodos de clonación para hacer una "copia" de un objeto. La razón por la que esto sucede es porque la asignación de Colors objColors = Session["Colors"]; es una asignación de referencia, esto es por diseño. Todo lo que está haciendo es hacer una referencia de alcance local a un objeto que ya existe. Eche un vistazo a IClonable para la clonación de objetos reales. Esto no es necesario tampoco puede implementar sus propios métodos de copia. También es posible que desee echar un vistazo a MemberwiseClone dependiendo de qué tan profundo sea su objeto.

2

Se accede al objeto por referencia en lugar de por su valor. See here. Hay varias formas de cambiar esto. Visite el sitio para obtener información detallada.

3

Pruebe un constructor de copias.

Ejemplo: link

1

No hay un camino construido en e implementado por defecto, pero se puede obtener mediante la implementación de este ICloneable y llamando MemberwiseClone. Esto solo funcionará para una copia poco profunda: si su objeto contiene otros objetos, deberá clonarlos también. Una aplicación sencilla sería:

public class Bla : ICloneable 
{ 
    string _someFieldToClone; 

    object ICloneable.Clone() 
    { 
     return this.Clone(); 
    } 

    public Bla Clone() 
    { 
     return (Bla)MemberwiseClone(); 
    } 
} 
+0

¿No está desactivado ICloneable? – erikkallen

+0

@erikkallen: No. http://msdn.microsoft.com/en-us/library/system.icloneable.aspx –

1

Esto lo hace porque no está copiando el objeto, sino la copia de una referencia al objeto. Usted puede hacer una copia profunda en C# fácilmente usando serialización binaria:

public static MemoryStream Serialize(object data) 
    { 

     MemoryStream streamMemory = new MemoryStream(); 
     BinaryFormatter formatter = new BinaryFormatter(); 
     formatter.AssemblyFormat = FormatterAssemblyStyle.Simple; 

     formatter.Serialize(streamMemory, data); 

     return streamMemory; 


    } 



    public static Object Deserialize(MemoryStream stream) 
    { 

     BinaryFormatter formatter = new BinaryFormatter(); 
     formatter.AssemblyFormat = FormatterAssemblyStyle.Simple; 
     return formatter.Deserialize(stream); 

    } 

Puede llamar a estos dos métodos, el primero toma un objeto y escribe sus datos a un MemoryStream. Luego puede llamar a Deserialize para obtener una nueva copia de un objeto basada en esa información.

Una última cosa que tus objetos necesitan ser Serializable haz esto poniendo el atributo Serializable en cada objeto.

0

Esto se debe a que los objetos objColors y Session ["Colors"] son ​​el mismo objeto.Si desea almacenar una copia y conservar el original, necesita hacer que su objeto sea razonable.

consulte los siguientes SO Q & A para un puntero en la dirección correcta: todos

Deep cloning objects

2

Otras respuestas han sugerido la clonación de una manera u otra. Una alternativa que puede o no ser adecuada para su situación particular es hacer que su tipo sea inmutable. Las operaciones que previamente mutaron tu tipo ahora devolverían una nueva instancia del tipo, tomando datos del objeto original y realizando los cambios apropiados, y dejando la instancia original intacta. Este es el enfoque que toma la clase String, por ejemplo.

Todavía tendrá que escribir el código apropiado para copiar los datos dentro de una instancia, por supuesto, pero el código trabajando con el tipo puede ser más simple.

Esto puede no ser apropiado en su caso, pero es una técnica al menos a considerar.

0

ya que los colores de clase es uno que ha creado, y supongo que usted es bastante nuevo en programación orientada a objetos, puede crear una copia Construtor como Stuart dijo con algo similar a lo siguiente:

public class Colors 
{ 
    public int Property1; 
    public int Property2; 
    public int Property3; 
    public Colors() 
    { 
    //Do your regular constructor here 
    } 
    public Colors(Colors colorToCopy) 
    { 
    this.Property1 = colorToCopy.Property1; 
    this.Property2 = colorToCopy.Property2; 
    this.Property3 = colorToCopy.Property3; 
    } 
} 

La clonación mediante serialización es una solución más generalizada y garantiza una copia profunda (lo que significa que copiará también las propiedades de las copias, así como las propiedades de las propiedades), pero es un poco más difícil de comprender. Con esta solución, si las Propiedades no son tipos de datos primitivos, esas no serían copias a menos que las haga explícitamente.

0

Cuando tiene una variable y le asigna un valor de sesión, obtendrá un puntero a ambas.

Colors objColors = (Colors)Session["Colors"]; 

Sesión [ "colores"] y objColors apuntan al mismo objeto en la memoria, a continuación, cuando se hizo un cambio en uno, los cambios se reflejan en ambos.

Si desea independencia, necesita obtener un copia profunda de su objeto. Usted tiene que implementar la interfaz IClonable de factura y todo ello 's clases relacionadas:

public class Colors: IClonable 
{ 
    public int Red; 
    public int Green; 
    public int Blue; 

    public object Clone() 
    { 
    return this.MemberwiseClone(); 
    } 
} 

Ahora usted tiene una copia en profundidad real del objeto que factura.

Colors objColors = (Colors)((Colors)Session["Colors"]).Clone(); 

Más información en: Objeto de la clonación con IClonable y MemberwiseClone dependiendo de qué tan profundo es su objeto.

Cuestiones relacionadas