如何将已知类型的列表动态添加到 Protobuf-net 格式化程序?

发布于 2024-11-15 10:43:33 字数 1958 浏览 2 评论 0原文

在一个项目中,我当前正在使用 DataContractSerializer 来序列化我的数据。出于性能原因,我想使用 Protobuf 代替。 我使用序列化程序在数据库中存储 blob,并且我希望保留 WCF 的数据版本控制功能,以便在项目在现实世界中发布后更轻松地处理数据协定修改。

这些 blob 的数据契约在编译时是未知的。 (配置文件中指定了“扩展”列表,因此扩展注册了它们在运行时知道的 DataContracts)

然而,似乎告诉 protobuf 已知类型的唯一方法是使用 [ProtoIninclude] 属性。

更具体地说,这是我想要序列化的示例。

[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() 不采用 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);
}

有解决方案吗?

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)containerSerialized.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 ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

来日方长 2024-11-22 10:43:33

由于您要序列化 ​​root 对象,因此在 v1(完全发布的 dll)中,您可以使用 Serializer.NonGeneric.SerializeWithLengthPrefix 和 DeserializeWithLengthPrefix API 来执行此操作,特别是对每个对象使用不同的字段号(标记) -type 序列化时,并使用接受类型解析器的反序列化重载将 irks-number 转换回类型。我目前不在电脑旁,但我可以稍后添加您需要的示例。

在“v2”中,这里有其他选项:

  • 您可以将属性(等)标记为 DynamicTypr=true,它存储其他类型元数据,使得该功能甚至适用于对象属性,但使其与您的模型更加紧密地联系在一起,
  • 您可以添加已知的通过灵活的类型模型在运行时生成子类型;但通常这不会来自 object,而且我仍在探索其可能的副作用(之前已将其作为一项功能请求)

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文