Shared binary

I am writing a binary serialiser / deserialser to convert several types of objects to / from a byte stream. Objects represent API commands and their associated responses for a device connected via Bluetooth or USB. I use BinaryWriterand BinaryReaderread / write to / from the stream.

The serializer is simple. Serialization bindings are marked with an attribute that determines the order in which they should be written to the byte stream. I repeat the properties with reflexive and overload resolution handlers, choosing the right Write(...)method BinaryWriter.

The deserializer is not so simple. Again, I can repeat the actions in a specific class of answers that I expect to determine the types that need to be read from the stream. The complex bit selects the correct method to call BinaryReaderin order to read the value I need. I was thinking of two approaches.

  • A large switch statement that invokes the correct method ReadXXXX()based on the type to be read.
  • Use the name of the type in which I need to create the method name that I need in the string, and then call the method using the transform.

Is there an easier way that I don't think about? This is just a shame, you cannot do overload permission based on the type of return you want.

+5
source share
2 answers

1 ( switch) . :

{
    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

, , . , 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, 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
   }
}
0

All Articles