Compartir a través de


Migración a protobuf-net (binario)

La biblioteca protobuf-net es un serializador basado en contrato para .NET que usa el formato de búferes de protocoloserialization binario. La API sigue los patrones típicos de .NET y es ampliamente comparable a XmlSerializer y DataContractSerializer.

Algunos comportamientos y características de protobuf-net serán notables durante las migraciones desde BinaryFormatter y muchos escenarios requieren aplicar atributos a los miembros.

  • De forma predeterminada, tanto los tipos públicos como no públicos se pueden serializar y el serializador que espera un constructor sin parámetros.
  • protobuf-net requiere que todos los tipos serializable se anoten con el atributo [ProtoContract]; este atributo puede especificar opcionalmente la propiedad SkipConstructor = true, que elimina la necesidad de cualquier constructor determinado.
  • Todos los campos no estáticos serializables y una propiedad deben anotarse con el atributo [ProtoMember(int identifier)]. Los nombres de miembro no están codificados en los datos. En su lugar, los usuarios deben elegir un entero positivo para identificar a cada miembro que debe ser único en ese tipo.
  • La herencia debe declararse explícitamente a través del atributo [ProtoInclude(...)] en cada tipo con subtipos conocidos.
  • Los campos de solo lectura se admiten de forma predeterminada.
  • Como alternativa,algunos tipos similares a tupla sin atributos son reconocidos por el patrón del constructor; un tipo con un constructor que tiene parámetros que coinciden (por nombre) con todos los miembros públicos declarados se interpretará como una tupla, y el orden de los parámetros se utilizará para inferir el identificador de dicho miembro.
  • Se recomienda encarecidamente usar el paquete en tiempo de diseñoprotobuf-net.BuildTools; esto ofrece advertencias en tiempo de compilación de errores comunes.

Migración paso a paso

  1. Busque todos los usos de BinaryFormatter.
  2. Asegúrese de que las rutas de acceso al código serialization estén cubiertas con pruebas, para que pueda verificar los cambios y evitar la introducción de errores.
  3. Instale el paquete protobuf-net (y, opcionalmente protobuf-net.BuildTools, ).
  4. Busque todos los tipos que se serializan con BinaryFormatter.
  5. En los tipos que pueda modificar:
    • Anotar con el atributo [ProtoContract] todos los tipos marcados con [Serializable] o implementar la interfaz de ISerializable. Si estos tipos no se exponen a otras aplicaciones (por ejemplo: escribe una biblioteca) que pueden usar serializadores diferentes como DataContractSerializer, puede quitar las anotaciones [Serializable] y ISerializable.
    • En el caso de los tipos derivados, aplique [ProtoInclude(...)] a sus tipos base (vea el siguiente ejemplo).
    • En todos los tipos que declaren cualquier constructor que acepte parámetros, agregue un constructor sin parámetros, o bien especifique SkipConstructor = true en el atributo [ProtoContract]. Deje un comentario que explique el requisito de protobuf-net (para que nadie lo quite por accidente).
    • Marque todos los miembros (campos y propiedades) que desea serializar con [ProtoMember(int identifier)]. Todos los identificadores deben ser únicos dentro de un solo tipo, pero los mismos números se pueden volver a usar en subtipos, siempre que la herencia esté habilitada.
  6. En el caso de los tipos que no se pueden modificar:
    • En el caso de los tipos que proporciona el propio .NET, puede usar ProtoBuf.Meta.RuntimeTypeModel.Default.CanSerialize(Type type) API para comprobar si son compatibles de forma nativa con protobuf-net.
    • Puede crear objetos de transferencia de datos dedicados (DTO) y asignarlos en consecuencia (podría usar el operador de conversión implícito para hacerlo).
    • Use la RuntimeTypeModel API para definir todo lo que permiten los atributos.
  7. Reemplace el uso de BinaryFormatter por ProtoBuf.Serializer.
-[Serializable]
+[ProtoContract]
+[ProtoInclude(2, typeof(Point2D))]
public class Point1D
{
+   [ProtoMember(1)]
    public int X { get; set; }
}

-[Serializable]
+[ProtoContract]
public class Point2D : Point1D
{
+   [ProtoMember(2)]
    public int Y { get; set; }
}