5

我不会使用 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; }
    }
}

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

4

1 回答 1

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; }
}
于 2016-08-29T22:04:19.473 回答