Publicidad:
La Coctelera

Info al día.

Articulos sobre los ultimos avances en tecnologia, desarrollo, arquitectura de software, y hardware. Actualizado diariamente.

11 Noviembre 2005

Serialización de objetos en .NET (2º Parte)

En esta serie de articulos, veremos en profundidad la serializacion de objetos en ambientes .NET

Serialización selectiva
Normalmente una clase contiene campos que no deberían serializarse. Por ejemplo, imagine que una clase almacena un Id. de subproceso en una variable miembro. Al deserializar la clase, puede que no se ejecute el subproceso almacenado para el Id. cuando la clase se serializó; por consiguiente, no tiene sentido serializar este valor. Para evitar que las variables miembro se serialicen, deben marcarse con el atributo NonSerialized:

[Serializable]
public class MyObject
{
public int n1;
[NonSerialized] public int n2;
public String str;
}

Serialización personalizada
Se puede personalizar el proceso de serialización implementando la interfaz ISerializable en un objeto. Esto resulta especialmente útil en los casos en los que el valor de una variable miembro no es válido tras la deserialización, pero es necesario proporcionar la variable con un valor con el fin de reconstruir el estado completo del objeto. La implementación de ISerializable supone implementar el método GetObjectData y un constructor especial que será utilizado al deserializar el objeto. En el siguiente ejemplo de código se muestra cómo implementar ISerializable en la clase MyObject desde una sección anterior.

[Serializable]
public class MyObject : ISerializable
{
public int n1;
public int n2;
public String str;

public MyObject()
{
}

protected MyObject(SerializationInfo info, StreamingContext context)
{
n1 = info.GetInt32("i");
n2 = info.GetInt32("j");
str = info.GetString("k");
}

public virtual void GetObjectData(SerializationInfo info,
StreamingContext context)
{
info.AddValue("i", n1);
info.AddValue("j", n2);
info.AddValue("k", str);
}
}
Al llamar a GetObjectData durante la serialización, deberá llenar el objeto SerializationInfo proporcionado con la llamada al método. Para ello, simplemente agregue las variables que se van a serializar como pares de nombres/valores. Se puede utilizar como nombre cualquier texto. Ahora tiene la libertad de decidir qué variables miembro se agregan a SerializationInfo, siempre que se serialicen datos suficientes para recuperar el objeto durante la deserialización. Las clases derivadas deben llamar al método GetObjectData en el objeto base si éste implementa ISerializable.

Es importante hacer hincapié en la necesidad de implementar ambos GetObjectData, así como el constructor especial cuando se agrega ISerializable a una clase. El compilador le advertirá si falta GetObjectData, pero dado que es imposible forzar la implementación de un constructor, no recibirá advertencias si el constructor está ausente y se enviará una excepción cuando intente deserializar la clase sin el constructor. El diseño actual se vió favorecido antes del método SetObjectData para solucionar posibles problemas de seguridad y control de versiones. Por ejemplo, un método SetObjectData debe ser público si está definido como parte de una interfaz, por tanto los usuarios deben escribir código para evitar que el método SetObjectData sea llamado varias veces. Es fácil imaginar los problemas que puede ocasionar una aplicación dañina que llama al método SetObjectData en un objeto en proceso de ejecutar una operación.

Durante la deserialización, se pasa el objeto SerializationInfo a una clase mediante el constructor proporcionado para dicho fin. Al deserializar el objeto, se ignoran todas las restricciones de visibilidad en el constructor, de forma que se puede marcar la clase como pública, protegida, interna o privada. Se recomienda proteger al constructor a no ser que la clase esté sellada, en cuyo caso éste deberá marcarse como privado. Para restaurar el estado del objeto, sólo hay que recuperar los valores de las variables de SerializationInfo con los nombres utilizados durante la serialización. Si la clase base implementa ISerializable, debe llamarse al constructor base para permitir que el objeto base restaure sus variables.

Al derivar una clase nueva de una que implementa ISerializable, la clase derivada debe implementar tanto el constructor como el método GetObjectData si tiene variables que necesitan serializarse. El miniprograma de código siguiente muestra cómo realizar este procedimiento utilizando la clase MyObject, mostrada previamente.

[Serializable]
public class ObjectTwo : MyObject
{
public int num;

public ObjectTwo() : base()
{
}

protected ObjectTwo(SerializationInfo si, StreamingContext context) :
base(si,context)
{
num = si.GetInt32("num");
}

public override void GetObjectData(SerializationInfo si,
StreamingContext context)
{
base.GetObjectData(si,context);
si.AddValue("num", num);
}
}
No olvide llamar a la clase base en el constructor de deserialización. De lo contrario, el constructor de la clase base no será llamado nunca y el objeto no se construirá totalmente tras la deserialización.

Los objetos se reconstruyen desde el interior. Durante la serialización, los métodos de llamada pueden ocasionar efectos secundarios no deseados, ya que es probable que éstos hayan llamado a referencias de objetos que no han sido deserializados antes de la llamada. Si la clase que se está deserializando implementa IDeserializationCallback, el método OnSerialization será llamado automáticamente cuando la totalidad del gráfico del objeto se deserialice. En este punto, se han restaurado todos los objetos secundarios mencionados. Una tabla hash es un ejemplo típico de una clase difícil de deserializar sin utilizar la escucha de evento descrito anteriormente. Resulta fácil recuperar los pares clave/valor durante la deserialización. Sin embargo, la agregación de estos objetos en la tabla hash puede ocasionar problemas, dado que no existe garantía de que las clases derivadas de la tabla se hayan deserializado. Por tanto, no es recomendable utilizar los métodos de llamada en una tabla hash.

Pasos en el proceso de serialización
Cuando se llama al método Serialize en un formateador, la serialización del objeto funciona según las siguientes reglas:

Se realiza una comprobación para determinar si el formateador tiene un selector suplente. Si es así, compruebe que éste controla objetos del tipo especificado. Si éste es el caso, se llama a ISerializable.GetObjectData en el selector suplente.
Si no existe un selector suplente o no controla el tipo especificado, se realizará una comprobación para determinar si el objeto está marcado con el atributo Serializable. En caso contrario, se utilizará SerializationException.
Si está marcado correctamente, compruebe si el objeto implementa ISerializable. Si es así, se llamará a GetObjectData en el objeto.
Si no implementa ISerializable, se utilizará la norma de serialización predeterminada, que consiste en serializar todos los campos no marcados como NonSerialized.
Control de versiones
.NET Framework admite el control de versiones y la ejecución página tras página. Todas las clases funcionarán en las distintas versiones si no se cambian las interfaces. Dado que las serializaciones tratan con variables miembro y no interfaces, preste atención al agregar o eliminar variables miembro en clases que se serializarán en las distintas versiones. Éste es el caso para clases que no implementan ISerializable. Cualquier cambio de estado en la versión actual, como la agregación de variables miembro, el cambio del tipo de variables o de sus nombres, significará que los objetos existentes del mismo tipo no podrán deserializarse correctamente si se serializaron en una versión anterior.

Si el estado de un objeto requiere cambiar versiones, los autores de clase tienen dos posibilidades:

Implementar ISerializable, lo que permite tomar un control preciso de los procesos de serialización y deserialización. Como resultado, se podrá agregar e interpretar correctamente el estado futuro durante la deserialización.
Marcar las variables miembro no esenciales con el atributo NonSerialized. Esta opción sólo debe utilizarse cuando se esperen cambios mínimos entre las diferentes versiones de una clase. Por ejemplo, al agregar una nueva variable a una versión posterior de una clase, la variable no puede marcarse como NonSerialized con el fin de asegurar que se mantenga compatible con las versiones anteriores.
Instrucciones de serialización
Utilice la serialización al diseñar nuevas clases, dado que una clase no puede serializarse tras compilarse. Algunas preguntas importantes: ¿debo enviar esta clase a los dominios de la aplicación?, ¿se utilizará esta clase con servicio remoto en algún momento?, ¿qué harán los usuarios con esta clase? Quizás deriven una nueva clase de la mía que necesita serializarse. Cuando tenga dudas, marque la clase como serializable. Es aconsejable marcar todas las clases como serializables a no ser que:

No se extiendan por ningún dominio de la aplicación. Si la serialización no es necesaria y la clase debe cruzar por un dominio de aplicación, derive la clase de MarshalByRefObject.
La clase almacena punteros especiales que sólo se aplican a la instancia actual de la clase. Si una clase contiene memoria no administrada o identificadores de archivos, por ejemplo, asegúrese de que estos campos estén marcados como NonSerialized o no deserialice la clase en ningún caso.
Algunos de los miembros de datos contienen información sensible. En este caso, será recomendable implementar ISerializable y serializar sólo los campos requeridos.

servido por Christian 1 comentario compártelo

1 comentario · Escribe aquí tu comentario

w3n

w3n dijo

muy buen articulo si señor, la serializacion en .net puede ser un poco oscura, este articulo la muestra de modo muy claro.

1 Febrero 2008 | 01:46 AM

Escribe tu comentario


Sobre mí

Avatar de Christian

Info al día.

Valparaiso, Chile
ver perfil »
contacto »
Christian Estay es estudiante de Ingenieria Informatica, esta afiliado al programa "Desarrollador 5 Estrellas" de Microsoft, y es participante activo en la comunidad MSDN Chile.

Fotos

Christian Estay German todavía no ha subido ninguna foto.

¡Anímale a hacerlo!

Buscar

suscríbete

Selecciona el agregador que utilices para suscribirte a este blog (también puedes obtener la URL de los feeds):

¿Qué es esto?

Crea tu blog gratis en La Coctelera