Hoy he tenido un problema al intentar duplicar un vector que contenía objetos de clase.
Hiciera lo que hiciera, todas las llamadas a parametros o intentos de crear un duplicado de un elemento de un vector, de tipo clase, me encontraba el mismo problema. Me devolvía siempre un objeto por referencia y nunca por valor.
Esto me estaba dando muchos problemas, por ejemplo, si quería crear un duplicado de un único elemento, por ejemplo extraer un equipo del vector de equipos, y que fuese independiente, no me dejaba, ya que al pasarse por referencia, todos los cambios que yo hacía en el duplicado que había extraido, se estaban cambiando automáticamente en el equipo original en el vector. Lo cual era un desastre.
De modo que la forma que he encontrado, es crear un documento serializandolo, descomponiendolo en pedazos de forma automática en memoria para disponer de dicho duplicado real, y no como hasta ahora, un simple punto de referencia en memoria.
Todas las clases que se deseen serializar, deben incluir esta sentencia delante de la declaración de la clase:
<Serializable()> Public Class clsEquipos
También hace falta en los Structures.
Se puede crear una función que realice el trabajo de serialización.
Imports System Imports System.Collections.Generic Imports System.Text Imports System.Runtime.Serialization Imports System.IO Imports System.Runtime.Serialization.Formatters.Binary Namespace Utilidades ''' ''' Realiza una clonación de un objeto de estructura compleja ''' Public Class clsCopiador Public Shared Function Duplicar(ByVal fuente) 'Creamos un stream en memoria Dim formatter As IFormatter = New BinaryFormatter() Dim stream As Stream = New MemoryStream() formatter.Serialize(stream, fuente) stream.Seek(0, SeekOrigin.Begin) 'Deserializamos la porción de memoria en el nuevo objeto Return formatter.Deserialize(stream) End Function End Class End Namespace
Otras opciones son mediante clones basicos y complejos.
Dejo aqui dos ejemplos, para desarrollar otro día.
Public Function ShallowCopy() As Person Return DirectCast(Me.MemberwiseClone(), Person) End Function Public Function DeepCopy() As Person Dim other As Person = DirectCast(Me.MemberwiseClone(), Person) other.IdInfo = New IdInfo(Me.IdInfo.IdNumber) Return other End Function
MemberwiseClone crea un clon superficial, donde solo copia el primer nivel de objetos, el resto queda por referencia. El efecto me parece desastroso.
Para hacerlo en profundidad hay que reenvíar todos los métodos, propiedades, etc, uno por uno, como se ve en DeepCopy, pero para lo que necesitaba yo, que era una copia completa y total y que no me implique tener que estar pendiente de cada mantenimiento en las propiedades, prefiero la serialización.
Nota: Tened cuidado si vais a volcar este tipo de información para hacer salvados a disco, ya que un salvado en 32 bits no lo podreis recuperar bien en uno de 64 bits y viceversa.
Dejo unas referencias para ampliar información:
Memberwise en MSDN
Memberwise en Java
Ejemplo completo en C#
Lección magistral de Guille