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; }
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…