我不会对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版本
答案 0 :(得分:3)
对{protobuf-net here DynamicType
DynamicType
的限制解释了您的困难(尽管不完全):
Type
- 存储类型的其他AssemblyQualifiedName
信息(默认情况下,它包含object
,尽管这可以由用户控制)。这使得序列化弱模型成为可能,即AsReference
用于属性成员,但是目前这仅限于契约类型(不是原语),并且不适用于具有继承的类型(这些限制可能会在以后删除)。与<snip>
一样,它使用了非常不同的布局格式。
那么,完全是指合同类型?如上所述,原始类型不是契约类型,而是所有类型?来自former project site:
我想说protobuf-net支持的[de]序列化有五种基本类型(不包括基本类型):
正常序列化。在此模式下,将写入标准协议缓冲区,协议缓冲区中的一个字段用于您使用ProtoMember标记的每个字段或属性,或者已由ImplicitFields自动选择的字段或属性。 ......
- 醇>
收集序列化。如果protobuf-net将特定数据类型标识为集合,则使用此模式对其进行序列化。值得庆幸的是,集合类型不需要任何ProtoContract或ProtoMember属性,这意味着您可以轻松地序列化List和T []等类型...
Dynamic type is not a contract-type: TestType[]
Protobuf-net使用“重复”字段(在协议缓冲区术语中)序列化集合。因此,您应该能够安全地更改版本之间的集合类型。例如,您可以序列化Foo [],然后将其反序列化为List。
因此,“合同类型”的序列化对应于本文中的“正常序列化” - 而集合是不是合同类型。这解释了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>