Nic*_*yle 21 c# serialization protocol-buffers protobuf-net
我有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);
Run Code Online (Sandbox Code Playgroud)
我在包含消息类型ID的序列化字节之前传递一个标头,我可以在一个巨大的switch语句中使用它返回预期的sublcass Type.使用下面的块,我收到错误: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;
Run Code Online (Sandbox Code Playgroud)
这是我用来通过网络发送消息的功能:
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());
}
}
Run Code Online (Sandbox Code Playgroud)
这个类,有基类,我正在序列化:
[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; }
}
}
Run Code Online (Sandbox Code Playgroud)
[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; }
}
}
Run Code Online (Sandbox Code Playgroud)
要接收对象:
//where "this.Ssl" is an SslStream.
BaseMessage message =
ProtoBuf.Serializer.DeserializeWithLengthPrefix<BaseMessage>(
this.Ssl, ProtoBuf.PrefixStyle.Base128);
Run Code Online (Sandbox Code Playgroud)
发送对象:
//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);
Run Code Online (Sandbox Code Playgroud)
Serializer.NonGeneric.Deserialize(Type, Stream); //Thanks, Marc.
Run Code Online (Sandbox Code Playgroud)
要么
RuntimeTypeModel.Default.Deserialize(Stream, null, Type);
Run Code Online (Sandbox Code Playgroud)
第一; 对于网络使用,有SerializeWithLengthPrefix和DeserializeWithLengthPrefix哪个处理长度(可选择带标签).在MakeGenericMethod乍看上去OK; 这实际上与我为实现RPC堆栈所做的工作的挂起提交非常紧密地联系起来:挂起的代码has an override of DeserializeWithLengthPrefix(实质上)a Func<int,Type>,将标记解析为类型以便更容易反序列化意外数据在飞行中.
如果消息类型实际上与BaseMessage和之间的继承有关BeginRequest,那么你不需要这个; 它总是进入层次结构中最顶层的合同类型并且向下运行(由于一些电线细节).
另外 - 我没有机会测试它,但以下可能会让它感到不安:
[ProtoMember(1)]
public override UInt16 messageType
{
get { return 1; }
}
Run Code Online (Sandbox Code Playgroud)
它标记为序列化,但没有设置值的机制.也许这就是问题?尝试删除[ProtoMember]这里,因为我不这很有用 - 它(就序列化而言),主要是[ProtoInclude(...)]标记的副本.
| 归档时间: |
|
| 查看次数: |
20166 次 |
| 最近记录: |