Udostępnij za pośrednictwem


Migrowanie do platformy protobuf-net (binarnej)

Biblioteka protobuf-net to serializator oparty na kontraktach dla platformy .NET, który używa formatuserialization protokołu binarnego. Interfejs API jest zgodny z typowymi wzorcami platformy .NET i jest zasadniczo porównywalny z XmlSerializer elementami i DataContractSerializer.

Niektóre zachowania i funkcje narzędzia protobuf-net będą godne uwagi podczas migracji z BinaryFormatterprogramu , a wiele scenariuszy wymaga zastosowania atrybutów do elementów członkowskich.

  • Domyślnie zarówno typy publiczne, jak i inne niż publiczne są serializowalne, a serializator oczekuje konstruktora bez parametrów.
  • Protobuf-net wymaga, aby każdy typ można serializować z atrybutem [ProtoContract] ; ten atrybut może opcjonalnie określić SkipConstructor = true właściwość, co eliminuje potrzebę dowolnego konstruktora.
  • Każde pole niestatyczne z możliwością serializacji i właściwość musi być oznaczona adnotacjami z atrybutem [ProtoMember(int identifier)] . Nazwy składowych nie są kodowane w danych. Zamiast tego użytkownicy muszą wybrać dodatnią liczbę całkowitą, aby zidentyfikować każdy element członkowski, który musi być unikatowy w obrębie tego typu.
  • Dziedziczenie musi być jawnie zadeklarowane za pośrednictwem [ProtoInclude(...)] atrybutu dla każdego typu ze znanymi podtypami.
  • Pola tylko do odczytu są domyślnie obsługiwane.
  • Alternatywnie niektóre nieprzypisania typów podobnych do krotki są rozpoznawane przez wzorzec konstruktora; typ z konstruktorem, który ma parametry zgodne (według nazwy) wszystkich zadeklarowanych publicznych elementów członkowskich, zostanie zinterpretowany jako krotka, a kolejność parametrów zostanie użyta do wywnioskowania identyfikatora dla tego elementu członkowskiego.
  • Korzystanie z protobuf-net.BuildTools pakietu w czasie projektowania jest zdecydowanie zalecane. Oferuje to ostrzeżenia w czasie kompilacji o typowych błędach.

Migracja krok po kroku

  1. Znajdź wszystkie użycia elementu BinaryFormatter.
  2. Upewnij się, że serialization ścieżki kodu są objęte testami, aby można było zweryfikować zmiany i uniknąć wprowadzania usterek.
  3. Zainstaluj protobuf-net pakiet (i opcjonalnie protobuf-net.BuildTools).
  4. Znajdź wszystkie typy, które są serializowane za pomocą polecenia BinaryFormatter.
  5. W przypadku typów, które można modyfikować:
    • Dodaj adnotację do [ProtoContract] atrybutu wszystkich typów oznaczonych za pomocą [Serializable] interfejsu lub zaimplementuj go ISerializable . Jeśli te typy nie są widoczne dla innych aplikacji (na przykład: piszesz bibliotekę), która może używać różnych serializatorów, takich jak DataContractSerializer, możesz usunąć [Serializable] adnotacje i ISerializable .
    • W przypadku typów pochodnych zastosuj się [ProtoInclude(...)] do ich typów bazowych (zobacz poniższy przykład).
    • Dla każdego typu, który deklaruje dowolny konstruktor, który akceptuje parametry, dodaj konstruktor bez parametrów lub określ SkipConstructor = true atrybut.[ProtoContract] Pozostaw komentarz, który wyjaśnia wymaganie protobuf-net (więc nikt nie usuwa go przypadkowo).
    • Oznacz wszystkie elementy członkowskie (pola i właściwości), które chcesz serializować za pomocą polecenia [ProtoMember(int identifier)]. Wszystkie identyfikatory muszą być unikatowe w obrębie jednego typu, ale te same liczby mogą być ponownie używane w podtypach, jeśli jest włączone dziedziczenie.
  6. W przypadku typów, których nie można modyfikować:
    • W przypadku typów udostępnianych przez samą platformę .NET można użyć interfejsu ProtoBuf.Meta.RuntimeTypeModel.Default.CanSerialize(Type type) API, aby sprawdzić, czy są one natywnie obsługiwane przez platformę protobuf-net.
    • Możesz utworzyć obiekty dedykowanego transferu danych (DTO) i odpowiednio je mapować (można użyć niejawnego operatora rzutowania).
    • Użyj interfejsu RuntimeTypeModel API, aby zdefiniować wszystkie dozwolone atrybuty.
  7. Zastąp użycie elementu ciągiem BinaryFormatter 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; }
}