If you don't want serialization richness — if you just want to write a structure to an array of bytes, consider a marshal class.
For example, consider a tar application in C #. The tar format is based on 512-byte blocks, and the first block in the series has a regular structure. Ideally, an application just wants to blitt data from a disk file, right into the structure. This method is Marshal.PtrToStructure . Here is the structure.
[StructLayout(LayoutKind.Sequential, Size=512)] internal struct HeaderBlock { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)] public byte[] name; // name of file. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] mode; // file mode [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] uid; // owner user ID [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] gid; // owner group ID [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] size; // length of file in bytes [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] mtime; // modify time of file [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] chksum; // checksum for header // ... more like that... up to 512 bytes.
Then here is a generic class that does blitting.
internal class RawSerializer<T> { public T RawDeserialize( byte[] rawData ) { return RawDeserialize( rawData , 0 ); } public T RawDeserialize( byte[] rawData , int position ) { int rawsize = Marshal.SizeOf( typeof(T) ); if( rawsize > rawData.Length ) return default(T); IntPtr buffer = Marshal.AllocHGlobal( rawsize ); Marshal.Copy( rawData, position, buffer, rawsize ); T obj = (T) Marshal.PtrToStructure( buffer, typeof(T) ); Marshal.FreeHGlobal( buffer ); return obj; } public byte[] RawSerialize( T item ) { int rawSize = Marshal.SizeOf( typeof(T) ); IntPtr buffer = Marshal.AllocHGlobal( rawSize ); Marshal.StructureToPtr( item, buffer, false ); byte[] rawData = new byte[ rawSize ]; Marshal.Copy( buffer, rawData, 0, rawSize ); Marshal.FreeHGlobal( buffer ); return rawData; } }
You can use this class with any structure. You must use LayoutKind.Sequential and restrict yourself to blittable types (mostly primitives and arrays of the same thing) in order to use this approach. It is fast and efficient in terms of code, performance and memory, but it is slightly limited in how it can be used.
Once you have an array of bytes, you can pass it through NetworkStream or the like, and then de-serialize using the same class on the other end.