Serialización en VB.NET


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