Как динамически добавить список известного типа в форматтер Protobuf-net? - PullRequest
1 голос
/ 12 июня 2011

В проекте я сейчас использую DataContractSerializer для сериализации моих данных. И я хотел бы использовать Protobuf вместо этого по соображениям производительности. Я использую сериализатор для хранения больших двоичных объектов внутри базы данных, и я хочу сохранить функции управления версиями данных WCF для более удобной обработки изменений контракта данных после выпуска проекта в реальном мире.

Контракты данных этих BLOB-объектов не известны во время компиляции. (Список «расширений» указан в файле конфигурации, поэтому расширения регистрируются DataContracts, которые они знают во время выполнения)

Однако кажется, что единственный способ сообщить protobuf об известном типе - это атрибут [ProtoInclude].

Чтобы быть более конкретным, вот пример того, что я хочу сериализовать.

[DataContract]
public class Mydata
{
    [DataMember(Order = 1)]
    public int Saved
    {
        get;
        set;
    }
}

[DataContract]
public class Container
{
    [DataMember(Order = 1)]
    public object Data
    {
        get;
        set;
    }
}

С DataContractSerializer вот как я:

[TestMethod]
public void SerializeWithDataContractSerializer()
{
    var container = new Container()
    {
        Data = new Mydata()
        {
            Saved = 1
        }
    };
    DataContractSerializer serializer = new DataContractSerializer(typeof(Container), new[] { typeof(Mydata) });
    var ms = new MemoryStream();
    serializer.WriteObject(ms, container);
    ms.Position = 0;
    var containerSerialized = (Container)serializer.ReadObject(ms);
    Assert.AreEqual(((Mydata)container.Data).Saved, ((Mydata)containerSerialized.Data).Saved);
}

С protobuf здесь, как я хотел сделать (но не возможно Serializer.CreateFormatter<T>() не принимает параметр knownTypes):

[TestMethod]
public void SerializeWithProtoBuf()
{
    var container = new Container()
    {
        Data = new Mydata()
        {
            Saved = 1
        }
    };

    var formatter = Serializer.CreateFormatter<Container>(new[] { typeof(Mydata) });
    var ms = new MemoryStream();
    formatter.Serialize(ms, container);
    ms.Position = 0;
    var containerSerialized = (Container)formatter.Deserialize(ms);
    Assert.AreEqual(((Mydata)container.Data).Saved, ((Mydata)containerSerialized.Data).Saved);
}

Есть решение?

1 Ответ

1 голос
/ 12 июня 2011

Поскольку вы сериализуете объект root , в v1 (полностью освобожденная dll) вы можете сделать это с помощью API Serializer.NonGeneric.SerializeWithLengthPrefix и DeserializeWithLengthPrefix, в частности, используя другой номер поля (тег) для каждого типа при сериализации и использовании перегрузки десериализации, которая принимает распознаватель типов , чтобы преобразовать число раздражителей обратно в тип.Я сейчас не за компьютером, но могу позже добавить пример, который вам нужен.

В "v2" здесь есть дополнительные опции:

  • вы можете пометить свойство (и т. д.) как DynamicTypr = true, в котором хранятся дополнительные метаданные типа, что делает эту работу даже для свойств объекта, но, делая ее более привязанной к вашей модели
  • , вы можете добавлять известные подтипы во время выполнения с помощью гибкого типа -модель;однако, как правило, это не из object, и я все еще изучаю возможные побочные эффекты этого (это было запрошено как функция ранее)
...