C# 使用protobuf CodedInputStream读取字节[]

C# 使用protobuf CodedInputStream读取字节[],c#,protocol-buffers,C#,Protocol Buffers,在下面的代码中,我想在c#中使用预定义的protobuf消息。我发现我能够编写并使用该方法获取已创建的方法,并生成一个字节[]: ContainerMessage containerMessage = new ContainerMessage(); containerMessage.Type = CommandType.Connect; containerMessage.Connect = new Connect(); containerMessage.Connect.ClientNam

在下面的代码中,我想在c#中使用预定义的protobuf消息。我发现我能够编写并使用该方法获取已创建的方法,并生成一个
字节[]

 ContainerMessage containerMessage = new ContainerMessage();
 containerMessage.Type = CommandType.Connect;
 containerMessage.Connect = new Connect();
 containerMessage.Connect.ClientName = "TemporaryClientName";

 byte[] stream = new byte[containerMessage.CalculateSize()];   
 using (Google.Protobuf.CodedOutputStream outstream = new Google.Protobuf.CodedOutputStream(stream))
 {
     containerMessage.WriteTo(outstream);
 }
这可以按预期工作,我可以检查消息,值与
字节[]
中的值一样。但是如果我尝试反序列化我刚刚创建的这个简单的
字节[]

  using (Google.Protobuf.CodedInputStream instream = new Google.Protobuf.CodedInputStream(stream))
  {
      instream.ReadMessage(containerMessage);
  }
它失败于:

Google.Protobuf.dll中发生类型为“Google.Protobuf.InvalidProtocolBufferException”的未处理异常

附加信息:协议消息包含无效标记(零)

这种从
字节[]反序列化的方法对protobuf正确吗?


Protobuf的定义是:

message ContainerMessage {
    CommandType type = 1;
    bool commandSuccess = 2;

    oneof message {
        Connect connect = 3;
    }
}

enum CommandType {
    START = 0;
    CONNECT = 2;
}

message Connect {
    string ClientName = 1;
    uint32 PushPullPort = 2;
}
并使用命令行生成CS文件:

protoc.exe -I=%CD% --csharp_out=..\GeneratedCsMessaging\ Connect.proto

codedOutStream
CodedInputStream
主要用于编译的原型类。声明并提到,如果要手动编写代码调用这两个类中的任何一个,则需要在每个值之前使用它们的
WriteTag
方法

但是,由于您希望使用Google Protobuf对任何System.IO.Stream进行序列化和解析,因此将按照预期完成此工作。这在本手册的解析和序列化部分中有很好的文档记录和描述。这对于快速掌握Google Protobuf的窍门非常有帮助。您可以看到
MemoryStream
用于序列化对象,而
Parse.ParseFrom
方法可用于从序列化数据中解析对象

正如你在使用Google.Protobuf对你的问题
的评论中提到的
是能够使用GoogleProtobuf功能的重要部分

编辑:在您的案例中,示例用法可能如下所示

        byte[] serializedBytes;

        ContainerMessage containerMessage = new ContainerMessage()
        {
            Connect = new Connect()
            {
                ClientName = "TemporaryClientName",
            },
            Type = CommandType.Connect,
        };

        using( MemoryStream stream = new MemoryStream())
        {
            containerMessage.WriteTo(stream);
            serializedBytes = stream.ToArray();
        }

        ContainerMessage parsedCopy = ContainerMessage.Parser.ParseFrom(serializedBytes);

您是否打算使用CodedOutput和CodedInputStream来反对解析和序列化部分中建议的任何System.IO.Stream?在MemoryStream中,使用CodedInputStream而不是CodedInputStream,反序列化是通过使用Parser.ParseFrom()完成的,Parser.ParseFrom()可用于每个已编译的Protobuf消息。我从未使用CodeDoutStream来序列化消息,但正如中所述,建议使用
WriteTag
方法。这可能解释了即将发生的错误,因为您的标记无效。由于CodedInputStream和CodeDoutpStream都声明“这个类通常由生成的代码使用”,我认为这两个类通常都不打算在生成的类之外使用。我无法建议如何准确地使用
CodeDoutpStream
(我的经验是使用protobuf net,您只需调用
Serializer.Serialize即可)(stream,obj)
,但您可以在此处轻松检查
字节[]
数据是否有效:(您还可以使用从您的模式为protobuf net或Google版本快速生成C,例如:)@Neele,我的问题本质上是两件事。1.我没有rtfm:(2.我没有使用Google.Protobuf;
,所以我不明白你可以直接将MemoryStream传递给Google Protobuf。如果你添加你的答案并包含此内容,我将接受。很好。要完全完成此操作,你应该添加一个示例,说明我的代码应该与内存流一起使用。如果你不这样做,我可以。@FantasticMrFox,我刚刚现在补充说:)