【发布时间】:2010-10-15 02:11:28
【问题描述】:
我有 2 个联网应用程序,它们应该相互发送序列化的 protobuf-net 消息。我可以序列化对象并发送它们,但是,我不知道如何反序列化接收到的字节。
我尝试对此进行反序列化,但失败并出现 NullReferenceException。
// Where "ms" is a memorystream containing the serialized
// byte array from the network.
Messages.BaseMessage message =
ProtoBuf.Serializer.Deserialize<Messages.BaseMessage>(ms);
我在包含消息类型 ID 的序列化字节之前传递了一个标头,我可以在一个巨大的 switch 语句中使用它来返回预期的子类类型。使用下面的块,我收到错误:System.Reflection.TargetInvocationException ---> System.NullReferenceException。
//Where "ms" is a memorystream and "messageType" is a
//Uint16.
Type t = Messages.Helper.GetMessageType(messageType);
System.Reflection.MethodInfo method =
typeof(ProtoBuf.Serializer).GetMethod("Deserialize").MakeGenericMethod(t);
message = method.Invoke(null, new object[] { ms }) as Messages.BaseMessage;
这是我用来通过网络发送消息的函数:
internal void Send(Messages.BaseMessage message){
using (System.IO.MemoryStream ms = new System.IO.MemoryStream()){
ProtoBuf.Serializer.Serialize(ms, message);
byte[] messageTypeAndLength = new byte[4];
Buffer.BlockCopy(BitConverter.GetBytes(message.messageType), 0, messageTypeAndLength, 0, 2);
Buffer.BlockCopy(BitConverter.GetBytes((UInt16)ms.Length), 0, messageTypeAndLength, 2, 2);
this.networkStream.Write(messageTypeAndLength);
this.networkStream.Write(ms.ToArray());
}
}
这个类,带有基类,我正在序列化:
[Serializable,
ProtoContract,
ProtoInclude(50, typeof(BeginRequest))]
abstract internal class BaseMessage
{
[ProtoMember(1)]
abstract public UInt16 messageType { get; }
}
[Serializable,
ProtoContract]
internal class BeginRequest : BaseMessage
{
[ProtoMember(1)]
public override UInt16 messageType
{
get { return 1; }
}
}
已修复,使用 Marc Gravell 的建议。我从只读属性中删除了 ProtoMember 属性。也切换到使用 SerializeWithLengthPrefix。这是我现在拥有的:
[Serializable,
ProtoContract,
ProtoInclude(50, typeof(BeginRequest))]
abstract internal class BaseMessage
{
abstract public UInt16 messageType { get; }
}
[Serializable,
ProtoContract]
internal class BeginRequest : BaseMessage
{
public override UInt16 messageType
{
get { return 1; }
}
}
接收一个对象:
//where "this.Ssl" is an SslStream.
BaseMessage message =
ProtoBuf.Serializer.DeserializeWithLengthPrefix<BaseMessage>(
this.Ssl, ProtoBuf.PrefixStyle.Base128);
发送一个对象:
//where "this.Ssl" is an SslStream and "message" can be anything that
// inherits from BaseMessage.
ProtoBuf.Serializer.SerializeWithLengthPrefix<BaseMessage>(
this.Ssl, message, ProtoBuf.PrefixStyle.Base128);
【问题讨论】:
-
我忘了说,我在 Windows 上的 .NET 3.5 中序列化并在 Mono 2.2 中反序列化,并且在每个平台上使用适当的 protobuf-net dll。
-
我会在大约半小时后回来阅读这篇文章并发布答案......现在必须运行,抱歉。顺便说一句 - 下一个版本内置了非通用包装器 - 目前仍在我的笔记本电脑上。
-
btw - 我正在合并我的本地副本,因此我可以提交更改以使这更容易。我有一个突出的测试失败,但它涵盖了新代码,所以如果有帮助,我很乐意提交它(标记为忽略)。
-
重新修复 - 我会进行一些更好的处理,以使这一点在未来更加明显......
-
我很欣赏提交代码的提议,但我使用泛型和基类让它工作。如果您认为它会更快或更少的代码行,我很乐意尝试一下。
标签: c# serialization protocol-buffers protobuf-net