Protobuf-net creating typemodel with interface and

2020-06-06 20:01发布

问题:

I'm trying to serialize a model using the great Protobuf-NET. I cannot use the attributes (objects are unknown at compile-time),so I constructed a TypeModel. My object model consist of a class TestDataObject, this class has a property of ITestDataExtension. The abstract baseclass TestDataExtensionBase implements this interface and the class TestDataExtension (myDataObjectExtA in code) inherits from this baseclass.

My TypeModel is constructed like this:

        System.IO.MemoryStream tmpMemoryStream = new System.IO.MemoryStream();
        RuntimeTypeModel model = TypeModel.Create();
        MetaType basetype = model.Add(typeof(TestDataObject), true);
        MetaType interfaceType = model.Add(typeof(ITestDataExtension), true);
        //MetaType extBaseType = interfaceType.AddSubType(100, typeof(TestDataExtensionBase));
        MetaType extType = interfaceType.AddSubType(200, myDataObjectExtA.GetType());
        model.Add(typeof(TestDataExtensionBase), true);
        model.Add(myDataObjectA.Ext.GetType(), true);
        model.CompileInPlace();
        model.Serialize(tmpMemoryStream, myDataObjectA);
        byte[] tmpDat = tmpMemoryStream.ToArray();

If I run the following the properties of the base class are not serialized, and I need them to be serialized.
In my opinion I should have added a subtype for the TestDataExtensionBase like this:

        MetaType extBaseType = interfaceType.AddSubType(100, typeof(TestDataExtensionBase));
        MetaType extType = extBaseType.AddSubType(200, myDataObjectExtA.GetType());

But this results in a : Unexpected sub-type: TestDataExtension. Does anyone known what I'm doing wrong? Any help would be appreciated.

回答1:

2 issues:

  • interface support is only currently provided for members, not root objects (due to the issues of multiple interface inheritance); the easiest way around this is to use a wrapper object with an interface member
  • it is necessary to define the sub-types in the model

I think the following does what you describe...?

using System;
using ProtoBuf.Meta;

interface ITest
{
    int X { get; set; }
}
abstract class TestBase : ITest
{
    public int X { get; set; } // from interface
    public int Y { get; set; }
}
class Test : TestBase
{
    public int Z { get; set; }
    public override string ToString()
    {
        return string.Format("{0}, {1}, {2}", X, Y, Z);
    }
}
class Wrapper
{
    public ITest Value { get; set; }
}
public class Program
{
    static void Main()
    {
        var model = TypeModel.Create();
        model.Add(typeof (ITest), false).Add("X")
                .AddSubType(10, typeof (TestBase));
        model.Add(typeof (TestBase), false).Add("Y")
                .AddSubType(10, typeof (Test));
        model.Add(typeof (Test), false).Add("Z");
        model.Add(typeof (Wrapper), false).Add("Value");

        Wrapper obj = new Wrapper {Value = new Test()
                {X = 123, Y = 456, Z = 789}};

        var clone = (Wrapper)model.DeepClone(obj);
        Console.WriteLine(clone.Value);
    }
}