Protobuf-net动态类型数组

时间:2013-07-15 14:01:59

标签: object serialization 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; }
    }
}

为什么会这样?我正在使用2.0.0.651版本

1 个答案:

答案 0 :(得分:3)

对{protobuf-net here DynamicType DynamicType的限制解释了您的困难(尽管不完全):

  

Type - 存储类型的其他AssemblyQualifiedName信息(默认情况下,它包含object,尽管这可以由用户控制)。这使得序列化弱模型成为可能,即AsReference用于属性成员,但是目前这仅限于契约类型(不是原语),并且不适用于具有继承的类型(这些限制可能会在以后删除)。与<snip>一样,它使用了非常不同的布局格式。

那么,完全是指合同类型?如上所述,原始类型不是契约类型,而是所有类型?来自former project site

  

我想说protobuf-net支持的[de]序列化有五种基本类型(不包括基本类型):

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

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

         

    Dynamic type is not a contract-type: TestType[]

         

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

  4.   

因此,“合同类型”的序列化对应于本文中的“正常序列化” - 而集合是不是合同类型。这解释了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; } } 打包到保证与合同类型对应的通用代理类型中,并封装必需的类型信息,如下所示:

<c:url var="registration" value="/registration"></c:url>
    <form:form role="form" commandName="user" action="${registration}" method="POST">
        <c:forEach items="${fields}" var="field" varStatus="loop">
            <p><c:out value="${field.name}" /> <c:if test="${field.required == true}"><c:out value=" *" /></c:if></p>
            <p><form:input path="name[${loop.index}]" type="hidden" value = "${field.name}" /></p>
            <p><form:input path="value[${loop.index}]" type="text" required = "${field.required}"/></p>
        </c:forEach>
        <button type="submit">Submit</button>
        <button type="reset">Reset</button>
    </form:form>