Protobuf-net 动态类型数组

Gor*_*yan 5 serialization object protobuf-net dynamictype

我不会使用 Protobuf-net 进行一些序列化,并会出现此代码片段的以下错误:

错误:

动态类型不是合同类型:TestType[]

片段:

using System.IO;
namespace QuickStart
{
    class Program
    {
        static void Main()
        {
            //FileAccess.ShowFileAccess();
            //Sockets.ShowSockets();

            var dto = new DataTransferType
            {
                ProtoDynamicProperty = new TestType[]
                {
                    new TestType {UselessProperty="AAA"},
                    new TestType{UselessProperty="BBB"},
                    new TestType{UselessProperty="CCC"}
                }
            };

            using (MemoryStream testStream = new MemoryStream())
            {
                ProtoBuf.Serializer.SerializeWithLengthPrefix(testStream, dto, ProtoBuf.PrefixStyle.Base128);
            }
        }


    }
    [ProtoBuf.ProtoContract]
    struct TestType
    {
        [ProtoBuf.ProtoMember(1)]
        public string UselessProperty { get; set; }
    }

    [ProtoBuf.ProtoContract]
    class DataTransferType
    {
        [ProtoBuf.ProtoMember(1, DynamicType = true)]
        public object ProtoDynamicProperty { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

任何想法为什么会发生这种情况?我正在使用 2.0.0.651 构建

dbc*_*dbc 4

您的困难可以通过在protobuf-net 的前项目站点DynamicType提到的限制来解释(尽管不完全) :

DynamicType- 使用Type类型存储附加信息(默认情况下它包括AssemblyQualifiedName,尽管这可以由用户控制)。这使得序列化弱模型成为可能,即 whereobject用于属性成员,但是目前这仅限于契约类型(不是基元),并且不适用于具有继承的类型(这些限制可能稍后会被删除)。与 一样AsReference,它使用非常不同的布局格式。

那么,合同类型到底是什么意思呢?如前所述,原始类型不是契约类型,但这就是全部吗?来自Protobuf-net:非官方手册:protobuf-net 中类型序列化的形式

我想说 protobuf-net 在逐个类型的基础上支持五种基本的[反]序列化(不包括原始类型):

  1. 正常序列化。在此模式下,会写入一个标准协议缓冲区,协议缓冲区中为您用 ProtoMember 标记的每个字段或属性或由 ImplicitFields 自动选择的每个字段或属性分配一个字段。...

  2. 集合序列化。如果 protobuf-net 将特定数据类型识别为集合,则使用此模式对其进行序列化。值得庆幸的是,集合类型不需要任何 ProtoContract 或 ProtoMember 属性,这意味着您可以轻松序列化 List 和 T[] 等类型......

    <snip>

    Protobuf-net 使用“重复”字段(在协议缓冲区术语中)序列化集合。因此,您应该能够安全地在版本之间更改集合类型。例如,您可以序列化 Foo[],然后将其反序列化为 List。

因此,“契约类型”的序列化对应于本文中的“正常序列化”——而集合不是契约类型。这解释了Dynamic type is not a contract-type: TestType[]异常消息。

作为解决方法,您可以将ProtoDynamicProperty内部封装为通用代理类型,保证与协定类型相对应并封装必需的类型信息,如下所示:

[ProtoContract]
public abstract class TypedObjectSurrogate
{
    protected TypedObjectSurrogate() { }

    [ProtoIgnore]
    public abstract object ObjectValue { get; }

    public static object CreateSurrogate<T>(T value)
    {
        if (value == null)
            return new TypedObjectSurrogate<T>();
        var type = value.GetType();
        if (type == typeof(T))
            return new TypedObjectSurrogate<T>(value);
        // Return actual type of subclass
        return Activator.CreateInstance(typeof(TypedObjectSurrogate<>).MakeGenericType(type), value);
    }
}

[ProtoContract]
public sealed class TypedObjectSurrogate<T> : TypedObjectSurrogate
{
    public TypedObjectSurrogate() : base() { }

    public TypedObjectSurrogate(T value)
        : base()
    {
        this.Value = value;
    }

    [ProtoIgnore]
    public override object ObjectValue
    {
        get { return Value; }
    }

    [ProtoMember(1)]
    public T Value { get; set; }
}

[ProtoBuf.ProtoContract]
class DataTransferType
{
    [ProtoBuf.ProtoIgnore]
    public object ProtoDynamicProperty { get; set; }

    [ProtoBuf.ProtoMember(1, DynamicType = true)]
    object ProtoDynamicPropertySurrogate
    {
        get
        {
            if (ProtoDynamicProperty == null)
                return null;
            return TypedObjectSurrogate.CreateSurrogate(ProtoDynamicProperty);
        }
        set
        {
            if (value is TypedObjectSurrogate)
                ProtoDynamicProperty = ((TypedObjectSurrogate)value).ObjectValue;
            else
                ProtoDynamicProperty = value;
        }
    }
}

[ProtoBuf.ProtoContract]
struct TestType
{
    [ProtoBuf.ProtoMember(1)]
    public string UselessProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)