Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
561 views
in Technique[技术] by (71.8m points)

object - Protobuf-net dynamictype array

I wont to do some serialization with Protobuf-net and getting folowing error for this code snippet:

The error:

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

The snippet:

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; }
    }
}

Any ideas why this happens? I`m using 2.0.0.651 build

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your difficulty is explained (albeit not fully) by the restrictions on DynamicType mentioned here at the former project site for protobuf-net:

DynamicType - stores additional Type information with the type (by default it includes the AssemblyQualifiedName, although this can be controlled by the user). This makes it possible to serialize weak models, i.e. where object is used for property members, however currently this is limited to contract types (not primitives), and does not work for types with inheritance (these limitations may be removed at a later time). Like with AsReference, this uses a very different layout format.

So, what exactly is meant by a contract type? As stated, primitive types are not contract types, but is that all? From Protobuf-net: the unofficial manual: Forms of type serialization in protobuf-net:

I would say there are five fundamental kinds of [de]serialization that protobuf-net supports on a type-by-type basis (not including primitive types):

  1. Normal serialization. In this mode, a standard protocol buffer is written, with one field in the protocol buffer for each field or property that you have marked with ProtoMember, or that has been auto-selected by ImplicitFields. ...

  2. Collection serialization. If protobuf-net identifies a particular data type as a collection, it is serialized using this mode. Thankfully, collection types do not need any ProtoContract or ProtoMember attributes, which means you can serialize types such as List and T[] easily...

    <snip>

    Protobuf-net serializes a collection using a "repeated" field (in protocol buffer lingo). Therefore, you should be able to safely change collection types between versions. For example, you can serialize a Foo[] and later deserialize it into a List.

So serialization of a "contract type" corresponds to "normal serialization" in this article -- and collections are not contract types. This explains the Dynamic type is not a contract-type: TestType[] exception message.

As a workaround, you can package your ProtoDynamicProperty inside a generic surrogate type that is guaranteed to correspond to a contract type and encapsulates the requisite type information, like so:

[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; }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...