Search code examples
c#serializationportable-class-library

How to serialize an object into an array of bytes (Portable Class Library)


I have an object that I want to serialize into byte[] in order to save it or move it around. Let's assume it's:

public class Message
{
    public MessageType MessageType { get; set; }

    public byte[] Body { get; set; }
}

public enum MessageType : byte
{
    Type1 = 1,
    Type2 = 2,
}

My code is a .Net 4.5, Windows 8.1 and Windows Phone 8.1 PCL (Portable Class Library), and all the libraries, examples, and answers I came across don't work with PCL, mostly because of their use of BinaryFormatter, which is not available in PCL.

So, how to go about it?


Solution

  • With a class that simple just write your own serializer using BinaryWriter and BinaryReader (Both useable in PCL projects)

    public class Message
    {
        public MessageType MessageType { get; set; }
    
        public byte[] Body { get; set; }
    
        public byte[] Serialize()
        {
            //Data will be serialized in the format 
            //  - MessageType (1 byte)
            //  - BodyLength (4 bytes)
            //  - Body (x Bytes)
    
            //We allocate a fixed buffer as we know the size already.
            var buffer = new byte[Body.Length + 5];
    
            using(var ms = new MemoryStream(buffer)
            {
                Serialize(ms);
            }
    
            //Return our buffer.
            return buffer 
        }
    
        //Just in case you have a stream instead of a byte[]
        public void Serialize(Stream stream)
        {
            using(var writer = new BinaryWriter(stream, Encoding.UTF8, true))
            {
                writer.Write((byte)this.MessageType);
                writer.Write(Body.Length);
                writer.Write(Body);
            }
        }
    
        public static Message Deserialize(byte[] data)
        {
            using(var ms = new MemoryStream(data))
            {
                return Message.Deserialize(ms);
            }
        }
    
        //Just in case you have a stream instead of a byte[]
        public static Message Deserialize(Stream data)
        {
            var message = new Message();
    
            //Use the default text encoding (does not matter for us) and leave the stream open.
            using(var reader = new BinaryReader(data, Encoding.UTF8, true))
            {
                //We do the same order of operations.
                message.MessageType = (MessageType)reader.ReadByte();
                var bodyLength = reader.ReadInt32();
                message.Body = reader.ReadBytes(bodyLength);
            }
    
            return message;
        }
    }
    

    Here is a simplified version if you are never going to use Streams for deserializing.

        public byte[] Serialize()
        {
            //Data will be serialized in the format 
            //  - MessageType (1 byte)
            //  - Body (x Bytes)
    
            //We allocate a fixed buffer as we know the size already.
            var data = new byte[Body.Length + 1];
    
            data[0] = (byte)this.MessageType;
            //We copy the data from Body in to data starting at index 1 in data.
            Array.Copy(Body, 0, data, 1, Body.Length);    
    
            return data;
        }
    
        public static Message Deserialize(byte[] data)
        {
            var message = new Message();
    
            //We do the same order of operations.
            message.MessageType = (MessageType)data[0];
    
            //Create a new array and copy the body data in to it.
            var body = new byte[data.Length - 1];
            Array.Copy(data, 1, body, 0, data.Length - 1);
    
            //Assign the body array to the property.
            message.Body = body;
    
            return message;
        }
    }