views:

119

answers:

1

I'm working on a project where I'm building a byte array that's almost like a serialization of the object graph. Each class is responsible for writing out it's own data, so I'm thinking about using a BinaryWriter and pass that instance around to my child objects and let them serialize themselves into this instead of creating temporary buffers (byte arrays) and merging them.

However I need to prepend each childdata with a byte that specifies the size of the following block, but that isn't known until the child has written all data, and by that time, the writer is positioned at the end of the childdata. I could of course create a temporary buffer and pass a temporary BinaryWriter to the child and then write the data to the "main" BinaryWriter after that, but that feels like a hackish solution.

Are there any alternative solutions? Is it maybe a bad idea to tamper with the position of the BinaryWriter? I would like to avoid creating temporary buffers/writers if possible and just let each child write to my "main" writer/buffer

The solution below might work, but is a little bit hackish. Are there any nicer solutions? (I haven't tested it so there's probably not perfectly byte aligned)

public abstract class BaseObject 
{
      public abstract void Serialize(BinaryWriter writer);
}



public class Program() 
{

  public static void Main() 
  {
       List<BaseObject> myChildren = new List<BaseObject>();

       // ... Initialize children here..

       MemoryStream memoryStream = new MemoryStream();
       BinaryWriter writer = new BinaryWriter(memoryStream);

       foreach (BaseObject child in myChildren) {
           writer.Write((byte)0); // Dummy placeholder. Length is a byte
           long sizePosition = writer.BaseStream.Position;
           child.Serialize(writer);
           long currentPosition = writer.BaseStream.Position;
           writer.Seek(sizePosition, SeekOrigin.Begin);
           writer.Write((byte)currentPosition-sizePosition);
           writer.Seek(currentPosition , SeekOrigin.Begin);
       }
   }
}
+2  A: 

I too was stumped with a very similar question recently and realized also that it seems you can/should practically only have one binary writer associated with a particular stream too because as soon as you close one binary writer (according to the documentation) the stream is also closed. I have come up with no better solutions than those you describe:

  1. Write the data to a MemoryStream, then write the size and contents of the memory stream to the main stream. This could be handy if you want to allow some objects to use another kind of writer besides a BinaryWriter.
  2. Remember your current position, write a 0 value, then the data block. Afterwards, rewind to the 0 value and replace it with the written size, then go back to the end.

I have opted for choice number 1. Although I haven't yet finished my implementation, it feels better to me to know the size of what's going to be written before writing anything to the stream. It feels more contrived to be writing dummy values and jumping around the stream. And it probably is more similar to how BinaryWriter writes strings internally. Are you, or have you considered, inheriting from BinaryWriter to add your own Write functions?

BlueMonkMN