我正在编写二进制序列化器/ deserialser来将许多对象类型转换为字节流。对象表示通过蓝牙或USB连接的设备的API命令及其相关响应。我正在使用BinaryWriter
& BinaryReader
在流中写入/读取。
序列化器很简单。要序列化的特性标记有一个属性,该属性指定将它们写入字节流的顺序。我使用反射和重载决策句柄迭代属性,选择Write(...)
的正确BinaryWriter
方法。
deserialiser并不那么简单。我再次可以遍历特定响应类中的特性,我期望确定需要从流中读取的类型。棘手的一点是选择正确的方法来调用BinaryReader
来读取我需要的值。我想到了两种方法。
ReadXXXX()
方法。我有没有想到更简单的方法?根据您想要的返回类型,您无法进行重载解析,这简直太可惜了。
答案 0 :(得分:1)
我在二进制解串器中使用了选项1(大开关语句)。一个更干净的方法可能是:
{
object result;
BinaryReader ...;
foreach (var propertyInfo in ...)
{
Func<BinaryReader, object> deserializer;
if (!supportedTypes.TryGetValue(propertyInfo.PropertyType, out deserializer))
{
throw new NotSupportedException(string.Format(
"Type of property '{0}' isn't supported ({1}).", propertyInfo.Name, propertyInfo.PropertyType));
}
var deserialized = deserializer(reader);
propertyInfo.SetValue(result, deserialized, null);
}
}
private static Dictionary<Type, Func<BinaryReader, object>> supportedTypes = new Dictionary<Type, Func<BinaryReader, object>>
{
{ typeof(int), br => br.ReadInt32() },
// etc
};
另一种选择是让命令类本身进行序列化:
interface IBinarySerializable
{
void Serialize(BinaryWriter toStream);
void Deserialize(BinaryReader fromStream);
}
然后在你的命令中:
abstract class Command : IBinarySerializable
{
}
class SomeCommand : Command
{
public int Arg1 { get; set; }
public void Serialize(BinaryWriter toStream)
{
toStream.Write(Arg1);
}
public void Deserialize(BinaryReader fromStream)
{
Arg1 = fromStream.ReadInt32();
}
}
通用序列化方法:
void Serialize<T>(T obj) where T : IBinarySerializable
{
obj.Serialize(_stream);
}
T Deserialize<T>() where T : new(), IBinarySerializable
{
var result = new T();
result.Deserialize(_stream);
return result;
}
但是这样你最终可能会复制一些代码。 (另一方面,派生类可以调用它们的父类类的Serialize / Deserialize,如果在你的场景中有意义的话,这很有效。)
答案 1 :(得分:0)
我不知道我是否完全明白你要做什么。但是听起来你应该仔细看看BinaryFormatter及其在.NET中的序列化代理。 BinaryFormatter允许您轻松地序列化和反序列化对象,序列化代理允许您添加自定义序列化和反序列化逻辑,并且还可以将一个对象重新映射到另一个对象。
看看这里:
的BinaryFormatter http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter.aspx
ISerializationSurrogate http://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializationsurrogate.aspx
SurrogateSelector http://msdn.microsoft.com/en-us/library/system.runtime.serialization.surrogateselector.aspx
SerializationBinder http://msdn.microsoft.com/en-us/library/system.runtime.serialization.serializationbinder.aspx
你还可以在这里看到一个小例子,其中我有一个方法可以将任何对象序列化为base64编码的字符串,然后是一个可以反序列化该字符串的反序列化方法。我还将一个SerializationBinder添加到格式化程序中,该格式化程序将MyOldClass类型的序列化重新映射到MyNewClass类型,并添加一个自定义ISerializationSurrogate,它可以在将对象添加到ner类之前处理对象中字段的值。
public class SerializeDeserializeExample {
public string Serialize(object objectToSerialize) {
using(var stream = new MemoryStream()) {
new BinaryFormatter().Serialize(stream, objectToSerialize);
return Convert.ToBase64String(stream.ToArray());
}
}
public object Deserialize(string base64String) {
using(var stream = new MemoryStream(Convert.FromBase64String(base64String))) {
var formatter = new BinaryFormatter();
var surrogateSelector = new SurrogateSelector();
formatter.SurrogateSelector = surrogateSelector;
formatter.Binder = new DeserializationBinder(surrogateSelector);
return formatter.Deserialize(stream);
}
}
}
public class MyDeserializationBinder : SerializationBinder {
private readonly SurrogateSelector surrogateSelector;
public MyDeserializationBinder(SurrogateSelector surrogateSelector) {
this.surrogateSelector = surrogateSelector;
}
public override Type BindToType(string assemblyName, string typeName) {
if(typeName.Equals("MyOldClass", StringComparison.InvariantCultureIgnoreCase)) {
return RemapToType();
}
return Type.GetType(String.Format("{0}, {1}", typeName, assemblyName));
}
private Type RemapToType() {
var remapToType = typeof(MyNewClass);
surrogateSelector.AddSurrogate(remapToType,
new StreamingContext(StreamingContextStates.All),
new MyCustomDeserializationSurrogate());
return remapToType;
}
}
public sealed class MyCustomDeserializationSurrogate : ISerializationSurrogate {
public void GetObjectData(Object obj, SerializationInfo info, StreamingContext context) {
throw new NotImplementedException();
}
public Object SetObjectData(Object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) {
var objectType = obj.GetType();
var fields = GetFields(objectType);
foreach(var fieldInfo in fields) {
var fieldValue = info.GetValue(fieldInfo.Name, fieldInfo.FieldType);
fieldValue = DoSomeProcessing(fieldValue);
fieldInfo.SetValue(obj, fieldValue);
}
return obj;
}
private static IEnumerable<FieldInfo> GetFields(Type objectType) {
return objectType.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly |
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
}
private static object DoSomeProcessing(object value){
//Do some processing with the object
}
}