Protobuf-net 泛型继承与封闭构造泛型 [英] Protobuf-net generic inheritance and closed constructed generic type

查看:121
本文介绍了Protobuf-net 泛型继承与封闭构造泛型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个相当复杂的继承层次结构,包括泛型,我们正在尝试使用 protobuf .net 进行序列化.不幸的是,它似乎无法正确处理这种情况.这就是层次结构的样子.

I have a fairly complex inheritance hierarchy including generics and we are trying to use protobuf .net for serialization purposes. Unfortunately it does not seem to be able to handle this case correctly. This is how the hierarchy looks like.

    [System.Runtime.Serialization.DataContract]
    [ProtoBuf.ProtoInclude(1000, typeof(GenericBaseClass<object>))]
    [ProtoBuf.ProtoInclude(1001, typeof(GenericBaseClass<string>))]
    public abstract class BaseClass
    {

        public int BaseProperty1 { set; get; }
        public int BaseProperty2 { set; get; }

        public BaseClass()
        {

        }

    }

    [System.Runtime.Serialization.DataContract]
    [ProtoBuf.ProtoInclude(1002, typeof(GenericDerivedClass<object>))]
    [ProtoBuf.ProtoInclude(1003, typeof(GenericDerivedClass<string>))]
    public abstract class GenericBaseClass<T> : BaseClass
    {
        /// <summary>
        /// 
        /// </summary>
        [System.Runtime.Serialization.DataMember(Order = 5)]
        public T ResponseProperty
        {
            get;
            set;
        }

        public GenericBaseClass()
        {
        }
    }

    [System.Runtime.Serialization.DataContract]
    [ProtoBuf.ProtoInclude(1004, typeof(DerivedClass1))]
    [ProtoBuf.ProtoInclude(1005, typeof(DerivedClass2))]
    public abstract class GenericDerivedClass<T> : GenericBaseClass<T>
    {
        public int AdditionalProperty { get; set; }

        public GenericDerivedClass()
        {

        }
    }

最后这些类由两个封闭构造的非泛型类实现

Finally these classes are implemented by two closed constructed non generic classes

    [System.Runtime.Serialization.DataContract]
    public class DerivedClass1 : GenericDerivedClass<string>             
    {
        [System.Runtime.Serialization.DataMember(Order = 6)]
        public int DerivedClass1Property { set; get; }
    }

    [System.Runtime.Serialization.DataContract]
    public class DerivedClass2 : GenericDerivedClass<object>
    {
        [System.Runtime.Serialization.DataMember(Order = 7)]
        public int DerivedClass2Property { set; get; }
    }

我编写了以下测试方法来序列化这些,但它给了我错误.

I have written the following test method to serialize these and it is giving me error.

    [TestMethod]
    public void SerializeDeserializeAndCompare()
    {            

        DerivedClass2 i = new DerivedClass2() { BaseProperty1 = 1, BaseProperty2 = 2, DerivedClass2Property = 3, ResponseProperty = new Object() };
        using (var file = System.IO.File.Create("test.bin"))
        {
            ProtoBuf.Serializer.Serialize(file, i);
        }

        using (var file = System.IO.File.OpenRead("test.bin"))
        {
            var o = ProtoBuf.Serializer.Deserialize<DerivedClass2>(file);
        }
    }

我得到的错误是

ProtoBuf.ProtoException:一个类型只能参与一个继承层次(CapitalIQ.DataGet.UnitTests.DataSetUnitTest+DerivedClass2)---> System.InvalidOperationException:一个类型只能参与一个继承层次

ProtoBuf.ProtoException: A type can only participate in one inheritance hierarchy (CapitalIQ.DataGet.UnitTests.DataSetUnitTest+DerivedClass2) ---> System.InvalidOperationException: A type can only participate in one inheritance hierarchy

这是 protobuf .net 的限制还是我做错了什么.我使用的是 r282 版本.

Is this a limitation of protobuf .net or am I doing something incorrect. I am using r282 version.

谢谢小黑

推荐答案

与所有属性一样,属性中包含的类型信息适用于泛型类型定义中的所有封闭类型.因此,您实际定义的(对 protobuf-net)是:

As with all attributes, the included type information on attributes apply to all closed types from the generic type definition. Thus, what you have actually defined (to protobuf-net) is:

BaseClass
: GenericBaseClass<object>
 : GenericDerivedClass<object>
  : DerivedClass1
  : DerivedClass2
 : GenericDerivedClass<string>
  : DerivedClass1
  : DerivedClass2
: GenericBaseClass<string>
 : GenericDerivedClass<object>
  : DerivedClass1
  : DerivedClass2
 : GenericDerivedClass<string>
  : DerivedClass1
  : DerivedClass2

如您所见,有很多重复项 - 这显然令人困惑.由于属性参数不能使用类型参数,这将留下添加某种奇怪谓词机制的选项,这让 IMO 非常混乱.IMO,最好手动建模(删除 ProtoInclude 属性).我怀疑你想要的模型是:

As you can see, there are lots of duplicates - which is clearly confusing. Since attribute arguments can't use type parameters, this would leave the option of adding some kind of odd predicate mechanism, which is IMO pretty confusing. IMO, it would be a better idea to model this manually (removing the ProtoInclude attributes). I suspect your intended model is:

BaseClass
: GenericBaseClass<object>
 : GenericDerivedClass<object>
  : DerivedClass2
: GenericBaseClass<string>
 : GenericDerivedClass<string>
  : DerivedClass1

protobuf-net 可以使用它,但要解释该模型需要v2"和 RuntimeTypeModel:

protobuf-net can work with that, but to explain the model requires "v2" and the RuntimeTypeModel:

还要注意 object 对 protobuf 来说有点问题;protobuf-net 可以使用 dynamic-type 选项来伪造它,但这...并不理想.它当然不能序列化 object,所以为了测试我替换了一个字符串.另请注意,BaseProperty1BaseProperty2AdditionalProperty 当前未标记为序列化,但可以很简单.

Note also that object is a bit of a problem for protobuf; protobuf-net can fake around it with the dynamic-type option, but that is... not ideal. It certainly can't serialize an object, so for the test I've substituted a string. Note also that BaseProperty1, BaseProperty2 and AdditionalProperty are not currently marked for serialization, but can be trivially.

无论如何:

RuntimeTypeModel.Default[typeof(BaseClass)]
    .AddSubType(10, typeof(GenericBaseClass<object>))
    .AddSubType(11, typeof(GenericBaseClass<string>));

RuntimeTypeModel.Default[typeof(GenericBaseClass<object>)]
    .AddSubType(10, typeof(GenericDerivedClass<object>));
RuntimeTypeModel.Default[typeof(GenericBaseClass<object>)][5].DynamicType = true; // object!
RuntimeTypeModel.Default[typeof(GenericDerivedClass<object>)]
    .AddSubType(10, typeof(DerivedClass2));

RuntimeTypeModel.Default[typeof(GenericBaseClass<string>)]
    .AddSubType(10, typeof(GenericDerivedClass<string>));
RuntimeTypeModel.Default[typeof(GenericDerivedClass<string>)]
    .AddSubType(10, typeof(DerivedClass1));

DerivedClass2 i = new DerivedClass2() { BaseProperty1 = 1, BaseProperty2 = 2, DerivedClass2Property = 3, ResponseProperty = "some string" };
using (var file = System.IO.File.Create("test.bin"))
{
    ProtoBuf.Serializer.Serialize(file, i);
}

using (var file = System.IO.File.OpenRead("test.bin"))
{
    var o = ProtoBuf.Serializer.Deserialize<DerivedClass2>(file);
}

您不必使用RuntimeTypeModel.Default - 事实上,我建议使用(和缓存)一个单独的类型模型;但 Serializer.Serialize 指向默认模型.如果您创建自定义模型 (TypeModel.Create),只需将其存储在某处并从那里使用 Serialize 等.

You don't have to use RuntimeTypeModel.Default - in fact, I recommend using (and caching) a separate type-model; but Serializer.Serialize points at the default model. If you create a custom model (TypeModel.Create) just store it somewhere and use the Serialize etc from there.

这篇关于Protobuf-net 泛型继承与封闭构造泛型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆