首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通用BinaryReader

通用BinaryReader
EN

Stack Overflow用户
提问于 2012-03-27 03:49:27
回答 2查看 3.4K关注 0票数 6

我正在编写二进制序列化/反序列化器,以将许多对象类型转换为/从字节流。对象表示通过蓝牙或USB连接的设备的API命令及其相关响应。我使用BinaryWriter & BinaryReader对流进行写入/读取。

连载很简单。要序列化的属性被标记为一个属性,该属性指定要写入字节流的顺序。我使用反射和重载解析来迭代属性,选择BinaryWriter的正确的BinaryWriter方法。

去列器并不是那么简单。同样,我可以迭代特定响应类中的属性,以确定需要从流中读取的类型。棘手之处在于选择正确的方法来调用BinaryReader来读取我需要的值。我想过两种方法。

  1. 一种大的开关语句,它根据要读取的类型调用正确的ReadXXXX()方法。
  2. 使用我需要的类型的名称在字符串中构建我需要的方法的名称,然后使用relection.

调用该方法。

有没有更简单的方法让我不去想?遗憾的是,您不能根据所需的返回类型执行重载解析。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-03-27 04:14:40

我在二进制反序列化器中使用了选项1(大开关语句)。一个更干净的方法可以是这样的:

代码语言:javascript
复制
{
    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
};

另一种选择是让命令类自己执行序列化:

代码语言:javascript
复制
interface IBinarySerializable
{
    void Serialize(BinaryWriter toStream);
    void Deserialize(BinaryReader fromStream);
}

然后在你的命令中:

代码语言:javascript
复制
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();
    }
}

和通用序列化方法:

代码语言:javascript
复制
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;
}

但这样你可能会复制一些代码。(另一方面,派生类可以调用它们的父类版本的序列化/反序列化,如果这在您的场景中是有意义的,并且工作得很好。)

票数 1
EN

Stack Overflow用户

发布于 2012-03-27 12:07:50

我不知道我是否完全明白你想做什么。但是,听起来您应该更仔细地查看BinaryFormatter及其在.NET中的序列化代理。BinaryFormatter允许您轻松地序列化和反序列化对象,序列化代理允许您添加自定义序列化和反序列化逻辑,还可以将一个对象重构到antoher。

请看这里:

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,该ISerializationSurrogate可以在将其添加到ner类之前处理对象中字段的值。

代码语言:javascript
复制
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
   }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9883139

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档