Mat*_*olf 10 c# serialization bytearray protocol-buffers protobuf-net
我查了但似乎无法看到如何将类直接序列化为字节数组,然后使用Marc Gravell的protobuf-net实现从字节数组反序列化.
编辑:我改变了问题并提供了代码,因为原始问题如何序列化为byte []而不必通过流是无足轻重的.我很抱歉.
更新的问题:有没有办法不必处理泛型,而是在通过构造函数传递时通过反射推断属性"MessageBody"的类型?我假设我无法序列化对象类型,对吗?当前的解决方案看起来非常麻烦,因为每次实例化一个新消息时我都需要传递MessageBody的类型.有更简洁的解决方案吗?
我想出了以下内容:
class Program
{
static void Main(string[] args)
{
Message<string> msg = new Message<string>("Producer", "Consumer", "Test Message");
byte[] byteArray = msg.Serialize();
Message<string> message = Message<string>.Deserialize(byteArray);
Console.WriteLine("Output");
Console.WriteLine(message.From);
Console.WriteLine(message.To);
Console.WriteLine(message.MessageBody);
Console.ReadLine();
}
}
[ProtoContract]
public class Message<T>
{
[ProtoMember(1)]
public string From { get; private set; }
[ProtoMember(2)]
public string To { get; private set; }
[ProtoMember(3)]
public T MessageBody { get; private set; }
public Message()
{
}
public Message(string from, string to, T messageBody)
{
this.From = from;
this.To = to;
this.MessageBody = messageBody;
}
public byte[] Serialize()
{
byte[] msgOut;
using (var stream = new MemoryStream())
{
Serializer.Serialize(stream, this);
msgOut = stream.GetBuffer();
}
return msgOut;
}
public static Message<T> Deserialize(byte[] message)
{
Message<T> msgOut;
using (var stream = new MemoryStream(message))
{
msgOut = Serializer.Deserialize<Message<T>>(stream);
}
return msgOut;
}
}
Run Code Online (Sandbox Code Playgroud)
我喜欢的是:
消息newMsg = new Message("Producer","Consumer",Foo); byte [] byteArray = newMsg.Serialize();
和消息msg = Message.Deserialize(byteArray);
(其中Deserialize是一个静态方法,它总是反序列化为Message类型的对象,只需要知道要将消息体反序列化的类型).
Mar*_*ell 10
这里有几个不同的问题,所以我会回答我能看到的内容:如果我错过了什么,请告诉我.
首先,如上所述,MemoryStream是获取byte []的最常用方法.这与大多数序列化程序一致 - 例如,XmlSerializer,BinaryFormatter和DataContractSerializer 也没有"作为byte []重载",但会接受MemoryStream.
泛型:你不需要使用泛型; v1有Serializer.NonGeneric,它将它包装在你身边.在v2中,"核心"是非泛型的,可以通过RuntimeTypeModel.Default访问; 当然,Serializer和Serializer.NonGeneric继续工作.
对于必须包含类型的问题:是的,protobuf规范假定接收方知道它们被给出的数据类型.这里一个简单的选择是使用一个简单的包装器对象作为"根"对象,具有数据的多个类型属性(其中只有一个非空).另一种选择可能源于通过ProtoInclude的内置继承支持(注意:作为实现细节,这两种方法是相同的).
在您的具体示例中,或许可以考虑:
[ProtoContract]
[ProtoInclude(1, typeof(Message<Foo>))]
.... More as needed
[ProtoInclude(8, typeof(Message<Bar>))]
public abstract class Message
{ }
[ProtoContract]
public class Message<T> : Message
{
...
}
Run Code Online (Sandbox Code Playgroud)
然后只需序列化<Message>
- API将自动创建正确的类型.
在最近的版本中,还有一个DynamicType选项,其中包含您的类型数据,例如:
[ProtoContract]
public class MyRoot {
[ProtoMember(1, DynamicType=true)]
public object Value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
这适用于包含契约类型实例的任何Value(但不适用于原语,理想情况下不涉及继承).
OP 发布的代码对我来说不太适用,以下是对 Marc Gravell 的更多建议进行的轻微改编。需要从 Message 继承以防止“不允许循环继承”,并且正如 GetBuffer 下面的代码注释中所指出的那样,也没有解决。
希望它可以帮助其他人,我花了好几个小时才让它全部工作......
[ProtoContract]
public abstract class Message
{
public byte[] Serialize()
{
byte[] result;
using (var stream = new MemoryStream())
{
Serializer.Serialize(stream, this);
result = stream.ToArray(); //GetBuffer was giving me a Protobuf.ProtoException of "Invalid field in source data: 0" when deserializing
}
return result;
}
}
[ProtoContract]
public class Message : Message
{
[ProtoMember(1)]
public string From { get; private set; }
[ProtoMember(2)]
public string To { get; private set; }
[ProtoMember(3)]
public T MessageBody { get; private set; }
public Message()
{ }
public Message(string from, string to, T messageBody)
{
this.From = from;
this.To = to;
this.MessageBody = messageBody;
}
public static Message Deserialize(byte[] message)
{
Message result;
using (var stream = new MemoryStream(message))
{
result = Serializer.Deserialize>(stream);
}
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
29118 次 |
最近记录: |