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
Your difficulty is explained (albeit not fully) by the restrictions on DynamicType
mentioned here at the former project site for protobuf-net:
DynamicType
- stores additionalType
information with the type (by default it includes theAssemblyQualifiedName
, although this can be controlled by the user). This makes it possible to serialize weak models, i.e. whereobject
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 withAsReference
, 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; }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With