Protobuf-net dynamictype array

dynamictype, object, protobuf-net, serialization

Solution

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):

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. ...

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

Problem

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

Original source

Related problems