protobuf-net:反序列化 Guid 属性的错误线型异常
Posted
技术标签:
【中文标题】protobuf-net:反序列化 Guid 属性的错误线型异常【英文标题】:protobuf-net: incorrect wire-type exception deserializing Guid properties 【发布时间】:2010-04-10 05:28:48 【问题描述】:我在使用 protobuf-net 反序列化 ORM 生成的实体的某些 Guid 属性时遇到问题。
这是代码的简化示例(重现了场景的大部分元素,但没有重现行为;我无法公开我们的内部实体,因此我正在寻找解释异常的线索)。假设我有一堂课,Account
有一个 AccountID
只读 guid 和一个 AccountName
读写字符串。我序列化并立即反序列化一个克隆。
反序列化时会引发Incorrect wire-type deserializing Guid
异常。
这里是示例用法...
Account acct = new Account() AccountName = "Bob's Checking" ;
Debug.WriteLine(acct.AccountID.ToString());
using (MemoryStream ms = new MemoryStream())
ProtoBuf.Serializer.Serialize<Account>(ms, acct);
Debug.WriteLine(Encoding.UTF8.GetString(ms.GetBuffer()));
ms.Position = 0;
Account clone = ProtoBuf.Serializer.Deserialize<Account>(ms);
Debug.WriteLine(clone.AccountID.ToString());
这是一个 ORM 类的示例(经过简化,但演示了我能想到的相关语义)。使用 shell 游戏通过暴露支持字段来反序列化只读属性(“不能写”本质上变成“不应该写”,但我们可以扫描代码以获取分配给这些字段的实例,因此该 hack 适用于我们的目的)。
同样,这不会重现异常行为;我正在寻找关于可能的线索:
[DataContract()]
[Serializable()]
public partial class Account
public Account()
_accountID = Guid.NewGuid();
[XmlAttribute("AccountID")]
[DataMember(Name = "AccountID", Order = 1)]
public Guid _accountID;
/// <summary>
/// A read-only property; XML, JSON and DataContract serializers all seem
/// to correctly recognize the public backing field when deserializing:
/// </summary>
[IgnoreDataMember]
[XmlIgnore]
public Guid AccountID
get return this._accountID;
[IgnoreDataMember]
protected string _accountName;
[DataMember(Name = "AccountName", Order = 2)]
[XmlAttribute]
public string AccountName
get return this._accountName;
set this._accountName = value;
XML、JSON 和 DataContract 序列化器似乎都可以很好地序列化/反序列化这些对象图,因此属性排列基本有效。我已经尝试过使用列表与单个实例、不同前缀样式等的 protobuf-net,但在反序列化时仍然总是得到“不正确的线型 ... Guid”异常。
所以具体的问题是,是否有任何已知的解释/解决方法?我不知道是什么情况(在实际代码中但不是示例中)可能导致它。
我们希望不必直接在实体层创建protobuf依赖;如果是这种情况,我们可能会创建代理 DTO 实体,其中所有公共属性都具有 protobuf 属性。 (这是我对所有声明性序列化模型的主观问题;这是一种普遍存在的模式,我理解它为什么会出现,但是 IMO,如果我们可以将人送上月球,那么“正常”应该是拥有对象和序列化合同解耦。;-) )
谢谢!
【问题讨论】:
@Paul - 只是基于您的调试行的一个随机想法......您是否在任何时候将二进制文件视为字符串?那行不通:marcgravell.blogspot.com/2010/03/binary-data-and-strings.html @marc - 合理的检查,但不,字符串输出只是为了快速的视觉增量。答案线程中的其他 cmets。谢谢! 【参考方案1】:同意,您不需要显式依赖 - DataMember
很好。并且 protobuf-net 使用相同的逻辑重新忽略等。您如何/在哪里存储数据?以我的经验,最常见的原因是人们正在用不同的数据覆盖缓冲区(或文件),而不是截断它(在流的末尾留下垃圾)as discussed here。这与您的场景有关吗?
【讨论】:
+1,绝对是一个很好的搜索曲目。尝试设置 ms.Capacity = Convert.ToInt32(ms.Length) (为什么 .Capacity 是 int 和 .Length 很长,顺便说一句?);仍然遇到相同的“不正确的线型反序列化 Guid”异常。 @Paul - 我没有写MemoryStream
;-p 关于电线类型问题 - 有没有可重现的例子?
@Paul - 重要的不是Capacity
;它是Length
。如果您要覆盖MemoryStream
,您必须 截断它(之前或之后都没有关系)。问题(覆盖)是,如果你写第一个对象并且它是(比如)254字节,那么你将位置设置为0并覆盖第二个对象(比如)120字节,那么流是*still 254 字节长。最后 134 个字节现在是垃圾。请参阅引用问题中的SetLength()
点。
@Marc Gravell - 谢谢!好提示;是的,我确实确保我正在从只写入一次的 MemoryStream 中读取。根据您的提示,我认为将其 .Capacity 截断为 .Length 可能会有所不同,但不幸的是没有。 (实际上,由于您提到的问题,我几乎从不重复使用内存流进行写入,而且我绝对不会在可重现的场景中。)
@Paul - 恐怕如果没有可重现的场景,我真的会很挣扎。另外 - 可能值得尝试 v2 代码(来自主干) - 还不是完全稳定的(并且没有正式发布),但如果它是一个错误,它可能已经修复v2.以上是关于protobuf-net:反序列化 Guid 属性的错误线型异常的主要内容,如果未能解决你的问题,请参考以下文章
我可以反序列化为 protobuf-net 中接口的只读属性吗?
是否可以在 Silverlight 中使用 protobuf-net 对私有属性进行(反)序列化?