Eseguire la migrazione a protobuf-net (binary)

La libreria protobuf-net è un serializzatore basato su contratto per .NET che usa il formato di serializzazione dei buffer di protocolli binari. L'API segue i modelli .NET tipici ed è ampiamente paragonabile a XmlSerializer e DataContractSerializer.

Alcuni comportamenti e funzionalità di protobuf-net saranno rilevanti durante le migrazioni da BinaryFormattere molti scenari richiedono l'applicazione di attributi ai membri.

  • Per impostazione predefinita, sia i tipi pubblici che non pubblici sono serializzabili, con il serializzatore che prevede un costruttore senza parametri.
  • protobuf-net richiede che ogni tipo serializzabile venga annotato con [ProtoContract] attributo. Questo attributo può facoltativamente specificare la SkipConstructor = true proprietà , che rimuove la necessità di qualsiasi costruttore specifico.
  • Ogni campo non statico serializzabile e una proprietà deve essere annotata con [ProtoMember(int identifier)] l'attributo . I nomi dei membri non sono codificati nei dati. Gli utenti devono invece selezionare un numero intero positivo per identificare ogni membro che deve essere univoco all'interno di tale tipo.
  • L'ereditarietà deve essere dichiarata in modo esplicito tramite [ProtoInclude(...)] attributo in ogni tipo con sottotipi noti.
  • I campi di sola lettura sono supportati per impostazione predefinita.
  • In alternativa, alcuni tipi non con attributi di tipo tuple vengono riconosciuti dal modello di costruttore. Un tipo con un costruttore con parametri corrispondenti (per nome) tutti i membri pubblici dichiarati verranno interpretati come una tupla e l'ordine dei parametri verrà usato per dedurre l'identificatore per tale membro.
  • L'uso del protobuf-net.BuildTools pacchetto in fase di progettazione è altamente consigliato, che offre avvisi in fase di compilazione di errori comuni.

Migrazione dettagliata

  1. Trovare tutti gli utilizzi di BinaryFormatter.
  2. Assicurarsi che i percorsi del codice di serializzazione siano trattati con i test, in modo da poter verificare le modifiche ed evitare di introdurre bug.
  3. Installare il protobuf-net pacchetto (e facoltativamente protobuf-net.BuildTools).
  4. Trovare tutti i tipi serializzati con BinaryFormatter.
  5. Per i tipi che è possibile modificare:
    • Annotare con [ProtoContract] l'attributo tutti i tipi contrassegnati con [Serializable] o implementare l'interfaccia ISerializable . Se questi tipi non sono esposti ad altre app (ad esempio, si scrive una libreria) che possono usare serializzatori diversi come DataContractSerializer, è possibile rimuovere le [Serializable] annotazioni e ISerializable .
    • Per i tipi derivati, applicare [ProtoInclude(...)] ai relativi tipi di base (vedere l'esempio seguente).
    • Per ogni tipo che dichiara qualsiasi costruttore che accetta parametri, aggiungere un costruttore senza parametri o specificare SkipConstructor = true sull'attributo [ProtoContract] . Lasciare un commento che spiega il requisito protobuf-net (quindi nessuno lo rimuove per caso).
    • Contrassegnare tutti i membri (campi e proprietà) da serializzare con [ProtoMember(int identifier)]. Tutti gli identificatori devono essere univoci all'interno di un singolo tipo, ma gli stessi numeri possono essere riutilizzati nei sottotipi se l'ereditarietà è abilitata.
  6. Per i tipi che non è possibile modificare:
    • Per i tipi forniti da .NET stesso, è possibile usare l'API ProtoBuf.Meta.RuntimeTypeModel.Default.CanSerialize(Type type) per verificare se sono supportati in modo nativo da protobuf-net.
    • È possibile creare oggetti DTO (Data Transfer Objects) dedicati ed eseguirne il mapping di conseguenza (è possibile usare l'operatore cast implicito per tale oggetto).
    • Usare l'API RuntimeTypeModel per definire tutti gli attributi consentiti.
  7. Sostituire l'utilizzo di BinaryFormatter con 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; }
}