Protobuf-net 错误:类型不是预期的,无法推断出合约:BlockHeader

问题描述 投票:0回答:3

尝试通过遵循此线程以及其他来源的信息来使 openstreetmap pbf 文件的反序列化正常工作:

Protobuf-net 反序列化开放街道地图

我目前正在使用 r480 的 protobug dll。我使用 protogen 从 osm 原型创建 csharp 类文件,但是当我在代码中遇到这一点时,我试图从流中读入:

BlockHeader header;
using (var tmp = new LimitedStream(file, length))
{
    header = Serializer.Deserialize<BlockHeader>(tmp); // exception occurs here
}

它抛出以下异常:

InnerException: System.InvalidOperationException
Message=Type is not expected, and no contract can be inferred: BlockHeader
Source=protobuf-net
StackTrace:
  at ProtoBuf.Meta.TypeModel.ThrowUnexpectedType(Type type) in C:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs:line 1115
  at ProtoBuf.Meta.TypeModel.TryDeserializeAuxiliaryType(ProtoReader reader, DataFormat format, Int32 tag, Type type, Object& value, Boolean skipOtherFields, Boolean asListItem, Boolean autoCreate, Boolean insideList) in C:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs:line 848
  at ProtoBuf.Meta.TypeModel.DeserializeCore(ProtoReader reader, Type type, Object value, Boolean noAutoCreate) in C:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs:line 582
  at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type, SerializationContext context) in C:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs:line 506
  at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type) in C:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs:line 488
  at ProtoBuf.Serializer.Deserialize[T](Stream source) in C:\Dev\protobuf-net\protobuf-net\Serializer.cs:line 69
  at OsmParserDemo.MainWindow.OsmParse() in C:\Users\crussell\Documents\Visual Studio 2010\Projects\OsmParseMadness\OsmParserDemo\MainWindow.xaml.cs:line 57
  at OsmParserDemo.MainWindow..ctor() in C:\Users\crussell\Documents\Visual Studio 2010\Projects\OsmParseMadness\OsmParserDemo\MainWindow.xaml.cs:line 28

因此,在将代码结构与 protobuf-net 示例的代码结构进行比较时,我的印象是我可能遗漏了一些关于识别每个成员的内容。这是正确的吗,还是我在这方面太落后了?非常感谢任何帮助或提示!

编辑:这是生成的 FileFormat.cs 类中的 BlockHeader 片段:

区块头

c# protobuf-net openstreetmap
3个回答
17
投票

添加代码文件后,一切都变得清晰起来。根据堆栈跟踪,您正在使用的库是 protobuf-net;但该 .cs 文件与 protobuf-net 没有任何关系。嗯,很少。 你看,(至少)有 2 个 c#/.net protobuf 实现,我认为你把它们混淆了:

    protobuf-csharp-port
  • 由 Jon Skeet 开发,是 Java 版本的直接移植,这意味着:它遵循相同的设计原则和 API。如果您同时使用 C# 和 Java,这很诱人。
  • protobuf-net
  • 由我开发,是一个从第一原则开始的实现,旨在成为惯用的 .NET,这意味着:它可以针对现有类型以代码优先的方式工作(基本上,如 XmlSerializer
    DataContractSerializer 
    等都可以),但如果你愿意的话也支持使用.proto
    
    
    
  • 令人困惑的是,它们都具有名为“protogen”的代码生成工具。 AFAIK,这种命名巧合只是自然的趋同/巧合,而不是计划(好的或恶意的)。

从 protobuf-csharp-port 的 protogen 生成的 c# 文件将与 protobuf-csharp-port 库一起使用

从 protobuf-net 的 protogen 生成的 c# 文件将与 protobuf-net 库一起使用

这是protobuf-net生成的版本,包括

BlockHeader


//------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // </auto-generated> //------------------------------------------------------------------------------ // Generated from: Foo.proto namespace ConsoleApplication9 { [global::System.Serializable, global::ProtoBuf.ProtoContract(Name=@"Blob")] public partial class Blob : global::ProtoBuf.IExtensible { public Blob() {} private byte[] _raw = null; [global::ProtoBuf.ProtoMember(1, IsRequired = false, Name=@"raw", DataFormat = global::ProtoBuf.DataFormat.Default)] [global::System.ComponentModel.DefaultValue(null)] public byte[] raw { get { return _raw; } set { _raw = value; } } private int _raw_size = default(int); [global::ProtoBuf.ProtoMember(2, IsRequired = false, Name=@"raw_size", DataFormat = global::ProtoBuf.DataFormat.TwosComplement)] [global::System.ComponentModel.DefaultValue(default(int))] public int raw_size { get { return _raw_size; } set { _raw_size = value; } } private byte[] _zlib_data = null; [global::ProtoBuf.ProtoMember(3, IsRequired = false, Name=@"zlib_data", DataFormat = global::ProtoBuf.DataFormat.Default)] [global::System.ComponentModel.DefaultValue(null)] public byte[] zlib_data { get { return _zlib_data; } set { _zlib_data = value; } } private byte[] _lzma_data = null; [global::ProtoBuf.ProtoMember(4, IsRequired = false, Name=@"lzma_data", DataFormat = global::ProtoBuf.DataFormat.Default)] [global::System.ComponentModel.DefaultValue(null)] public byte[] lzma_data { get { return _lzma_data; } set { _lzma_data = value; } } private byte[] _bzip2_data = null; [global::ProtoBuf.ProtoMember(5, IsRequired = false, Name=@"bzip2_data", DataFormat = global::ProtoBuf.DataFormat.Default)] [global::System.ComponentModel.DefaultValue(null)] public byte[] bzip2_data { get { return _bzip2_data; } set { _bzip2_data = value; } } private global::ProtoBuf.IExtension extensionObject; global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing) { return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); } } [global::System.Serializable, global::ProtoBuf.ProtoContract(Name=@"BlockHeader")] public partial class BlockHeader : global::ProtoBuf.IExtensible { public BlockHeader() {} private string _type; [global::ProtoBuf.ProtoMember(1, IsRequired = true, Name=@"type", DataFormat = global::ProtoBuf.DataFormat.Default)] public string type { get { return _type; } set { _type = value; } } private byte[] _indexdata = null; [global::ProtoBuf.ProtoMember(2, IsRequired = false, Name=@"indexdata", DataFormat = global::ProtoBuf.DataFormat.Default)] [global::System.ComponentModel.DefaultValue(null)] public byte[] indexdata { get { return _indexdata; } set { _indexdata = value; } } private int _datasize; [global::ProtoBuf.ProtoMember(3, IsRequired = true, Name=@"datasize", DataFormat = global::ProtoBuf.DataFormat.TwosComplement)] public int datasize { get { return _datasize; } set { _datasize = value; } } private global::ProtoBuf.IExtension extensionObject; global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing) { return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); } } }

结论:

要么使用 protobuf-net protogen,要么使用 protobuf-csharp-port 库。不可混合搭配。


3
投票

public IEnumerable<T> Deserialize<T>(string path) { using (var stream = File.Open(path, FileMode.Open, FileAccess.Read)) { var item = Serializer.Deserialize<IEnumerable<T>>(stream); return item; } }

当我将 
IEnumerable<T>

更改为

List<T>
时,问题就消失了。我猜 ProtoBuff 对接口一无所知,你应该指定你想要反序列化的非抽象/接口类型。

UPD:

结论:您应该反序列化为被序列化的类型对象。没有基本类型。


0
投票
[ProtoContract]

属性,而我的属性上没有

[ProtoMember(..)]
属性。
    

© www.soinside.com 2019 - 2024. All rights reserved.