c# - serializacion - ¿Es posible hacer la serialización binaria.NET de un objeto cuando no tienes el código fuente de la clase?
serializacion y deserializacion c# (5)
Cree una nueva clase, herede la clase existente que no está marcada con el atributo de serialización e implemente la interfaz ISerializable.
Si la clase está sellada, entonces puede usar Json.NET y luego convertirla a binario y viceversa (Sucks a lo grande, úsela si nada más puede ayudar :)).
Estoy usando BinaryFormatter
para hacer la serialización binaria de algunos objetos en C #. Sin embargo, algunos de los objetos contienen clases a las que accedo a través de una DLL y no tienen el código fuente, por lo que no puedo marcarlas con el atributo Serializable
. ¿Existe alguna manera directa de serializarlos de todos modos? Tengo una solución que implica tomar la clase NoSource
y crear una nueva clase SerializableNoSource
para la cual el constructor toma un objeto NoSource
y extrae toda la información que necesito de él, pero es raro. ¿Hay mejores alternativas?
Creo que la manera más limpia sería implementar Interface ISerializable y administrar la serialización y el proceso inverso. En MSDN podemos encontrar:
la serialización no se puede agregar a una clase después de haber sido compilada ...
Es posible que pueda usar Mono.Cecil para agregar el [SerializableAttribute]
a las clases, pero no lo haría si hay otra forma de lograr el resultado deseado.
Estoy de acuerdo con @Servy, si el autor de la clase no anticipó que se serializaría, no debería intentar serializarlo directamente. Entonces estás haciendo lo correcto desde el punto de vista arquitectónico. Para que su enfoque actual sea menos "hacky", considere implementar ISerializable para las clases que contienen referencias a objetos no serializables.
Puede crear un sustituto de serialización .
Imagine que tenemos una clase definida en un ensamblaje al que no tenemos control y que se ve así:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public DriversLicense License;
}
// An instance of this type will be part of the object graph and will need to be
// serialized also.
public class DriversLicense
{
public string Number { get; set; }
}
Para serializar este objeto, deberá definir un sustituto de serialización para cada tipo en el gráfico de objetos.
Para crear un sustituto de serialización, simplemente necesita crear un tipo que implemente la interfaz ISerializationSurrogate
:
public class PersonSurrogate : ISerializationSurrogate
{
/// <summary>
/// Manually add objects to the <see cref="SerializationInfo"/> store.
/// </summary>
public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
Person person = (Person) obj;
info.AddValue("Name", person.Name);
info.AddValue("Age", person.Age);
info.AddValue("License", person.License);
}
/// <summary>
/// Retrieves objects from the <see cref="SerializationInfo"/> store.
/// </summary>
/// <returns></returns>
public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
{
Person person = (Person)obj;
person.Name = info.GetString("Name");
person.Age = info.GetInt32("Age");
person.License = (DriversLicense) info.GetValue("License", typeof(DriversLicense));
return person;
}
}
public class DriversLicenseSurrogate : ISerializationSurrogate
{
/// <summary>
/// Manually add objects to the <see cref="SerializationInfo"/> store.
/// </summary>
public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
DriversLicense license = (DriversLicense)obj;
info.AddValue("Number", license.Number);
}
/// <summary>
/// Retrieves objects from the <see cref="SerializationInfo"/> store.
/// </summary>
/// <returns></returns>
public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
{
DriversLicense license = (DriversLicense)obj;
license.Number = info.GetString("Number");
return license;
}
}
Luego, debe informar a su IFormatter
sobre los sustitutos definiendo e inicializando un SurrogateSelector
y asignándolo a su IFormatter
.
private static void SerializePerson(Person person)
{
if (person == null)
throw new ArgumentNullException("person");
using (var memoryStream = new MemoryStream())
{
//Configure our surrogate selectors.
var surrogateSelector = new SurrogateSelector();
surrogateSelector.AddSurrogate(typeof (Person), new StreamingContext(StreamingContextStates.All),
new PersonSurrogate());
surrogateSelector.AddSurrogate(typeof (DriversLicense), new StreamingContext(StreamingContextStates.All),
new DriversLicenseSurrogate());
//Serialize the object
IFormatter formatter = new BinaryFormatter();
formatter.SurrogateSelector = surrogateSelector;
formatter.Serialize(memoryStream, person);
//Return to the beginning of the stream
memoryStream.Seek(0, SeekOrigin.Begin);
//Deserialize the object
Person deserializedPerson = (Person) formatter.Deserialize(memoryStream);
}
}
El uso de un sustituto de serialización no es sencillo, y en realidad puede volverse bastante detallado cuando el tipo que intenta serializar tiene campos privados y protegidos que deben ser serializados.
Pero como ya está serializando manualmente los valores que necesita, no creo que sea un problema. El uso de un sustituto es una forma más uniforme de manejar un escenario como este y debería hacerlo sentir más cómodo.