Packing a class into a byte array - would [Serializable] do the trick?
-
I'm looking for a way to represent an instantiated class as a byt array (and populate an instantiated class frm a byte array. I was hoping that [Serializable] would be the magic bullet but it seems I was wrong - or do I just not understand how to use [Serializable] properly? Let's say I have:
public class myClass
{
public byte myByte1;
public byte myByte2;
public ushort myUshort1;
public ushort myUshort2;public myClass()
{
this.myByte1 = 0x01;
this.myByte2 = 0x02;
this.myUshort1 = 0x0304;
this.myUshort2 = 0x0506;
}
}Now, if I instantiate this class with
myClass myInstance = new myClass()
the member variales will hold the values as defined by the constructor. I'd like to be able to view the contents of the class as an array of bytes (ie.{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}
). So I was thinking that if the class is serializable and I write the seraialized stream to a byte array (or write a byte array to the associated stream) I'd be able to pull it off, something like this:MemoryStream memStream = new MemoryStream();
BinaryFormatter binFormatter = new BinaryFormatter();
binFormatter.Serialize(memStream, myInstance);
byte[] myBytes = memStream.ToArray();But myBytes is 183 bytes in size (as opposed to the expected 6 bytes) once this is finished and the contents of myBytes makes no sense to me whatsoever. Am I on completely the wrong track here or is there hope?
-
I'm looking for a way to represent an instantiated class as a byt array (and populate an instantiated class frm a byte array. I was hoping that [Serializable] would be the magic bullet but it seems I was wrong - or do I just not understand how to use [Serializable] properly? Let's say I have:
public class myClass
{
public byte myByte1;
public byte myByte2;
public ushort myUshort1;
public ushort myUshort2;public myClass()
{
this.myByte1 = 0x01;
this.myByte2 = 0x02;
this.myUshort1 = 0x0304;
this.myUshort2 = 0x0506;
}
}Now, if I instantiate this class with
myClass myInstance = new myClass()
the member variales will hold the values as defined by the constructor. I'd like to be able to view the contents of the class as an array of bytes (ie.{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}
). So I was thinking that if the class is serializable and I write the seraialized stream to a byte array (or write a byte array to the associated stream) I'd be able to pull it off, something like this:MemoryStream memStream = new MemoryStream();
BinaryFormatter binFormatter = new BinaryFormatter();
binFormatter.Serialize(memStream, myInstance);
byte[] myBytes = memStream.ToArray();But myBytes is 183 bytes in size (as opposed to the expected 6 bytes) once this is finished and the contents of myBytes makes no sense to me whatsoever. Am I on completely the wrong track here or is there hope?
-
Here are many additional information is added with serialization like assembly name, version, class name, structure, ........ All this information is necessary to deserialize this object
-
Aha, that makes sense. So does that mean that [Serializable] would not be the proper route then? Would you have any other suggestions?
Dewald wrote:
Aha, that makes sense. So does that mean that [Serializable] would not be the proper route then?
Yes, if the array size is not critical. If critical you have to realize you own convertion like:
public class myClass { public byte myByte1; public byte myByte2; public ushort myUshort1; public ushort myUshort2; public myClass() { } public static byte[] ToByteArray(myClass value) { byte[] result = new byte[6]; result[0] = value.myByte1; result[1] = value.myByte2; unchecked { result[2] = (byte)(value.myUshort1 / 256); result[3] = (byte)(value.myUshort1 - result[2] * 256); result[4] = (byte)(value.myUshort2 / 256); result[5] = (byte)(value.myUshort2 - result[4] * 256); } return result; } public static myClass FromByteArray(byte[] array) { myClass result = new myClass(); result.myByte1 = array[0]; result.myByte2 = array[1]; result.myUshort1 = (ushort)(array[2] * 256 + array[3]); result.myUshort2 = (ushort)(array[4] * 256 + array[5]); return result; } }
P.S. usort is 16-bit type so we need to store it into two bytes. -
Dewald wrote:
Aha, that makes sense. So does that mean that [Serializable] would not be the proper route then?
Yes, if the array size is not critical. If critical you have to realize you own convertion like:
public class myClass { public byte myByte1; public byte myByte2; public ushort myUshort1; public ushort myUshort2; public myClass() { } public static byte[] ToByteArray(myClass value) { byte[] result = new byte[6]; result[0] = value.myByte1; result[1] = value.myByte2; unchecked { result[2] = (byte)(value.myUshort1 / 256); result[3] = (byte)(value.myUshort1 - result[2] * 256); result[4] = (byte)(value.myUshort2 / 256); result[5] = (byte)(value.myUshort2 - result[4] * 256); } return result; } public static myClass FromByteArray(byte[] array) { myClass result = new myClass(); result.myByte1 = array[0]; result.myByte2 = array[1]; result.myUshort1 = (ushort)(array[2] * 256 + array[3]); result.myUshort2 = (ushort)(array[4] * 256 + array[5]); return result; } }
P.S. usort is 16-bit type so we need to store it into two bytes.Yip, this is exactly what I've been doing up until now but I was just hoping that there wuld be a more elegant sollution. The thing is that I have various classes that I'd like to be able to pack into byte arrays (basically the classes are just messages that I need to transmit and receive over a TCP socket). I was hoping that I could write a base class that provides a method of packing the class into an array and then derrive all the other classes from that class. That way I wouldn't have to implement a huge amount of tedious code to pack every individual member variable of the class into the array.
-
Yip, this is exactly what I've been doing up until now but I was just hoping that there wuld be a more elegant sollution. The thing is that I have various classes that I'd like to be able to pack into byte arrays (basically the classes are just messages that I need to transmit and receive over a TCP socket). I was hoping that I could write a base class that provides a method of packing the class into an array and then derrive all the other classes from that class. That way I wouldn't have to implement a huge amount of tedious code to pack every individual member variable of the class into the array.
-
Yip, this is exactly what I've been doing up until now but I was just hoping that there wuld be a more elegant sollution. The thing is that I have various classes that I'd like to be able to pack into byte arrays (basically the classes are just messages that I need to transmit and receive over a TCP socket). I was hoping that I could write a base class that provides a method of packing the class into an array and then derrive all the other classes from that class. That way I wouldn't have to implement a huge amount of tedious code to pack every individual member variable of the class into the array.
Dewald, last night I got an idea: in unmanaged C++ we just need to look at the object as byte array:
// Some & and * have to be added to next code to say we are working with references MyClass myCl = new MyClass(); byte[] array = meCl; // this operation is allowed fo references // coping this array to new one or sending it as is through TCP socet
But in .Net we haven't references (that is very good, in my opinion), but we have some classes that allow to work with objects by references way. One of them is System.Runtime.InteropServices.Marshal I have never worked with, just herad about it. I have being looking through this and find some pairs of static methods wich can help you (I guess): To get IntPTR from your object: public static extern void StructureToPtr(object structure, IntPtr ptr, bool fDeleteOld); public static object PtrToStructure(IntPtr ptr, Type structureType) To copy to byte array: public static void Copy(IntPtr source, byte[] destination, int startIndex, int length); public static void Copy(byte[] source, int startIndex, IntPtr destination, int length) Or public static extern byte ReadByte(object ptr, int ofs); public static extern void WriteByte(IntPtr ptr, int ofs, byte val); Regards. P.S. IntPtr (intPointer) is Net analog of C++ pointers -- modified at 2:48 Saturday 9th June, 2007 -
Dewald, last night I got an idea: in unmanaged C++ we just need to look at the object as byte array:
// Some & and * have to be added to next code to say we are working with references MyClass myCl = new MyClass(); byte[] array = meCl; // this operation is allowed fo references // coping this array to new one or sending it as is through TCP socet
But in .Net we haven't references (that is very good, in my opinion), but we have some classes that allow to work with objects by references way. One of them is System.Runtime.InteropServices.Marshal I have never worked with, just herad about it. I have being looking through this and find some pairs of static methods wich can help you (I guess): To get IntPTR from your object: public static extern void StructureToPtr(object structure, IntPtr ptr, bool fDeleteOld); public static object PtrToStructure(IntPtr ptr, Type structureType) To copy to byte array: public static void Copy(IntPtr source, byte[] destination, int startIndex, int length); public static void Copy(byte[] source, int startIndex, IntPtr destination, int length) Or public static extern byte ReadByte(object ptr, int ofs); public static extern void WriteByte(IntPtr ptr, int ofs, byte val); Regards. P.S. IntPtr (intPointer) is Net analog of C++ pointers -- modified at 2:48 Saturday 9th June, 2007I've done the copying for value object (structure). One thing I can't make is to get a pointer (IntPtr) from reference object (class).
public struct myStuct { public byte myByte1; public byte myByte2; public ushort myUshort1; public ushort myUshort2; private const int MY_SIZE = 6; public static byte[] ToByteArray(myStuct source) { // Allocating an unmanagement memory for marshaling IntPtr pointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(MY_SIZE); // Copying instance to allocated memory System.Runtime.InteropServices.Marshal.StructureToPtr(source, pointer, false); byte[] result = new byte[MY_SIZE]; // Coping filled memory to byte array System.Runtime.InteropServices.Marshal.Copy(pointer, result, 0, MY_SIZE); return result; } public static myStuct FromByteArray(byte[] source) { if (source == null) throw new ArgumentNullException("Source array can not be null"); if (source.Length != MY_SIZE) throw new ArgumentException("Source array's size has to be " + MY_SIZE + " bytes"); // Allocating an unmanagement memory for marshaling IntPtr pointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(MY_SIZE); // Coping byte array to allocated memory System.Runtime.InteropServices.Marshal.Copy(source, 0, pointer, MY_SIZE); // Creating instance from unmanagment memory myStuct result = (myStuct)System.Runtime.InteropServices.Marshal.PtrToStructure(pointer, typeof(myStuct)); return result; } }
-
I've done the copying for value object (structure). One thing I can't make is to get a pointer (IntPtr) from reference object (class).
public struct myStuct { public byte myByte1; public byte myByte2; public ushort myUshort1; public ushort myUshort2; private const int MY_SIZE = 6; public static byte[] ToByteArray(myStuct source) { // Allocating an unmanagement memory for marshaling IntPtr pointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(MY_SIZE); // Copying instance to allocated memory System.Runtime.InteropServices.Marshal.StructureToPtr(source, pointer, false); byte[] result = new byte[MY_SIZE]; // Coping filled memory to byte array System.Runtime.InteropServices.Marshal.Copy(pointer, result, 0, MY_SIZE); return result; } public static myStuct FromByteArray(byte[] source) { if (source == null) throw new ArgumentNullException("Source array can not be null"); if (source.Length != MY_SIZE) throw new ArgumentException("Source array's size has to be " + MY_SIZE + " bytes"); // Allocating an unmanagement memory for marshaling IntPtr pointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(MY_SIZE); // Coping byte array to allocated memory System.Runtime.InteropServices.Marshal.Copy(source, 0, pointer, MY_SIZE); // Creating instance from unmanagment memory myStuct result = (myStuct)System.Runtime.InteropServices.Marshal.PtrToStructure(pointer, typeof(myStuct)); return result; } }
Thanks for all the effort AikinX, I also discovered this approach but, like you, I couldn't get it to work for classes. I never even bothered to try using it for structures (silly of me) and this will do nicely. It is a bit of a pity that I have to resort to unmanage code. I would have prefered if there was a way that I could do this without having to use pointers, and there probably is which is still elluding me. Either way, for now, this will do. Thanks again.
-
Thanks for all the effort AikinX, I also discovered this approach but, like you, I couldn't get it to work for classes. I never even bothered to try using it for structures (silly of me) and this will do nicely. It is a bit of a pity that I have to resort to unmanage code. I would have prefered if there was a way that I could do this without having to use pointers, and there probably is which is still elluding me. Either way, for now, this will do. Thanks again.