Protobuf 继承和泛型

Sim*_*ams 4 .net c# protocol-buffers protobuf-net

我正在尝试使用 ProtoBuf net 序列化具有以下格式的类的对象树:

[ProtoContract]
class MySpecialCollectionList<T> : List<MySpecialCollection<T>>
{
    [ProtoMember(1)]
    public string Name { get; set; }
}

[ProtoContract]
class MySpecialCollection<T> : List<Special<T>>
{
    [ProtoMember(1)]
    public string Name { get; set; }
}

[ProtoContract]
class Special<T>
{
    [ProtoMember(1)]
    public string Name { get; set; }
    [ProtoMember(2)]
    public string Description { get; set; }

    [ProtoMember(3)]
    private readonly T _source; 
    T Source { get { return _source; } }

    private Special()
    {
    }

    public Special(T source) 
    { 
        _source = source; 
    }
}

interface IBeast
{
    string Name { get; set; }
}
[ProtoContract]
class Ant : IBeast
{
    [ProtoMember(1)]
    public string Name { get; set; }
}
[ProtoContract]
class Cat : IBeast
{
    [ProtoMember(1)]
    public string Name { get; set; }
}
[ProtoContract]
class Dog : IBeast
{
    [ProtoMember(1)]
    public string Name { get; set; }
}

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        MySpecialCollectionList<IBeast> collectionList = GetSpecialCollectionList();
        using (var fs = File.Create(@"c:\temp\protobuftest.bin"))
        {
            Serializer.Serialize(fs, collectionList);

            fs.Close();
        }
    }

    private MySpecialCollectionList<IBeast> GetSpecialCollectionList()
    {
        var ant = new Ant() { Name = "Mr Ant" };
        var cat = new Cat() { Name = "Mr Cat" };
        var dog = new Dog() { Name = "Mr Dog" };

        var Special = new Special<IBeast>(ant);

        var specialCollection1 = new MySpecialCollection<IBeast>() {
            {new Special<IBeast>(ant)},
            {new Special<IBeast>(cat)},
            {new Special<IBeast>(dog)}
        };
        specialCollection1.Name = "Special Collection1";


        var specialCollection2 = new MySpecialCollection<IBeast>() {
            {new Special<IBeast>(ant)},
            {new Special<IBeast>(dog)}
        };
        specialCollection2.Name = "Special Collection2";

        var specialCollectionList = new MySpecialCollectionList<IBeast>() {
            specialCollection1, specialCollection2 };

        specialCollectionList.Name = "Special Collection List";
        return specialCollectionList;
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意我正在序列化 ( MySpecialCollectionList<T>)的类是如何从 a 派生的List<SomeOtherClass<T>>,而不仅仅是List<T>.

我正在努力找出将“ProtoInclude”属性放在哪里以使其序列化 MySpecialCollectionList 中的所有项目。任何帮助将非常感激。

Mar*_*ell 6

继承是不是一个问题在这里,因为即使A : B它是不正确的Foo<A> : Foo<B>。请注意,protobuf-net 不会使用非默认构造函数,尽管可以跳过构造函数,直接绑定到字段(甚至readonly)。虽然您可能有 6 T,但我看不出(从代码中)它会怀疑您打算使用哪种封闭类型,如果已知封闭类型,则应该设置。

如果您有 aFoo<SomeBaseClass>和许多继承自的具体类型,SomeBaseClass那么标记将 o on SomeBaseClass

但是,如果您有一个具体的场景我可以用来重现您的问题,我会很乐意看一看。


更新重新编辑:

例子中有几个关键点:

  • 与大多数结合的API常见,XmlSerializer的和IIRC DataContractSerializer的,一个项目是任一列表XOR与值的项目; 如果一个集合(实现的东西IList)本身具有属性,它们将不会被序列化;在这里,封装优于继承,即一个Name一个列表的东西(而不是一个Name一个列表)
  • protobuf-net v1 不支持基于接口的序列化;v2确实如此,但与 XmlSerializer 和 DataContractSerializer 一样,您需要明确告诉它它需要期待什么;非常好,不过,我们可以将其移动[ProtoMember]到界面本身

这是 v2 中的完整工作版本:

using System.Collections.Generic;
using ProtoBuf;
[ProtoContract]
class MySpecialCollectionList<T>
{
    [ProtoMember(1)]
    public string Name { get; set; }

    private readonly List<MySpecialCollection<T>> items = new List<MySpecialCollection<T>>();
    [ProtoMember(2)]
    public List<MySpecialCollection<T>> Items { get { return items; } }
}

[ProtoContract]
class MySpecialCollection<T>
{
    [ProtoMember(1)]
    public string Name { get; set; }

    private readonly List<Special<T>> items = new List<Special<T>>();
    [ProtoMember(2)]
    public List<Special<T>> Items { get { return items; } }
}

[ProtoContract]
class Special<T>
{
    [ProtoMember(1)]
    public string Name { get; set; }
    [ProtoMember(2)]
    public string Description { get; set; }

    [ProtoMember(3)]
    private readonly T _source;
    T Source { get { return _source; } }

    private Special()
    {
    }

    public Special(T source)
    {
        _source = source;
    }
}
[ProtoContract]
[ProtoInclude(2, typeof(Ant))]
[ProtoInclude(3, typeof(Cat))]
[ProtoInclude(4, typeof(Dog))]
interface IBeast
{
    [ProtoMember(1)]
    string Name { get; set; }
}
[ProtoContract]
class Ant : IBeast
{
    public string Name { get; set; }
}
[ProtoContract]
class Cat : IBeast
{
    public string Name { get; set; }
}
[ProtoContract]
class Dog : IBeast
{
    public string Name { get; set; }
}

public static class Form1
{

    private static void Main()
    {
        MySpecialCollectionList<IBeast> collectionList = GetSpecialCollectionList();
        var copy = Serializer.DeepClone(collectionList);
    }

    private static MySpecialCollectionList<IBeast> GetSpecialCollectionList()
    {
        var ant = new Ant() { Name = "Mr Ant" };
        var cat = new Cat() { Name = "Mr Cat" };
        var dog = new Dog() { Name = "Mr Dog" };

        var Special = new Special<IBeast>(ant);

        var specialCollection1 = new MySpecialCollection<IBeast>() {Items =
            {new Special<IBeast>(ant),
            new Special<IBeast>(cat),
            new Special<IBeast>(dog)}
        };
        specialCollection1.Name = "Special Collection1";


        var specialCollection2 = new MySpecialCollection<IBeast>()
        {
            Items =
            {new Special<IBeast>(ant),
            new Special<IBeast>(dog)}
        };
        specialCollection2.Name = "Special Collection2";

        var specialCollectionList = new MySpecialCollectionList<IBeast>()
        {
            Items ={
            specialCollection1, specialCollection2 }
        };

        specialCollectionList.Name = "Special Collection List";
        return specialCollectionList;
    }
}
Run Code Online (Sandbox Code Playgroud)