开发者

How to add dynamically a list of known type to a Protobuf-net formatter?

In a project, I'm currently using a DataContractSerializer to serialize my data. And I'd like to use Protobuf instead for performance reason. I use a serializer to store blobs inside a database, and I want to keep the data versioning features of WCF to handle more easily data contract modifications once the project is released in the real world.

The data contracts of these blobs are not known at compile time. (A list of "extension" is specified in the config file and so the extensions register DataContracts they know at runtime)

However it seems that the only way to tell protobuf about known type is with the [ProtoInclude] attribute.

To be more specific, here is an example of what I want to serialize.

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

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

With DataContractSerializer here how I do :

[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)conta开发者_运维问答inerSerialized.Data).Saved);
}

With protobuf here how I wanted to do (but not possible Serializer.CreateFormatter<T>() does not take a knownTypes parameter) :

[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);
}

Any solution ?


Since you are serialising a root object, in v1 (the fully released dll) you can do this using the Serializer.NonGeneric.SerializeWithLengthPrefix and DeserializeWithLengthPrefix API, in particular using a different field-number (tag) per-type when serialising, and using the deserialize overload that accepts a type-resolver to translate a irks-number back into a Type. I'm not at a PC currently but I can add an example later of you need.

In "v2" there are additional options here:

  • you can mark a property (etc) as DynamicTypr=true, which stores additional type metadata making this work even for object properties, but making it a bit more tied to your model
  • you can add known sub-types at runtime via the flexible type-model; however generally this wouldn't be from object, and I am still exploring possible side-effects of this (it has been requested as a feature previously)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜