How do I convert a structure to a byte array in C#?
I have defined a structure like this:
public struct CIFSPacket
{
public uint protocolIdentifi
This can be done very straightforwardly.
Define your struct explicitly with [StructLayout(LayoutKind.Explicit)]
int size = list.GetLength(0);
IntPtr addr = Marshal.AllocHGlobal(size * sizeof(DataStruct));
DataStruct *ptrBuffer = (DataStruct*)addr;
foreach (DataStruct ds in list)
{
*ptrBuffer = ds;
ptrBuffer += 1;
}
This code can only be written in an unsafe context. You have to free addr
when you're done with it.
Marshal.FreeHGlobal(addr);
@Abdel Olakara answer donese not work in .net 3.5, should be modified as below:
public static void ByteArrayToStructure<T>(byte[] bytearray, ref T obj)
{
int len = Marshal.SizeOf(obj);
IntPtr i = Marshal.AllocHGlobal(len);
Marshal.Copy(bytearray, 0, i, len);
obj = (T)Marshal.PtrToStructure(i, typeof(T));
Marshal.FreeHGlobal(i);
}
You can use Marshal (StructureToPtr, ptrToStructure), and Marshal.copy but this is plataform dependent.
Serialization includes Functions to Custom Serialization.
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
SerializationInfo include functions to serialize each member.
BinaryWriter and BinaryReader also contains methods to Save / Load to Byte Array (Stream).
Note that you can create a MemoryStream from a Byte Array or a Byte Array from a MemoryStream.
You can create a method Save and a method New on your structure:
Save(Bw as BinaryWriter)
New (Br as BinaryReader)
Then you select members to Save / Load to Stream -> Byte Array.
Looks like a predefined (C level) structure for some external library. Marshal is your friend. Check:
http://geekswithblogs.net/taylorrich/archive/2006/08/21/88665.aspx
for a starter how to deal with this. Note that you can - with attributes - define things like byte layout and string handling. VERY nice approach, actually.
Neither BinaryFormatter Nor MemoryStream are done for that.
I know this is really late, but with C# 7.3 you can do this for unmanaged structs or anything else that's unmanged (int, bool etc...):
public static unsafe byte[] ConvertToBytes<T>(T value) where T : unmanaged {
byte* pointer = (byte*)&value;
byte[] bytes = new byte[sizeof(T)];
for (int i = 0; i < sizeof(T); i++) {
bytes[i] = pointer[i];
}
return bytes;
}
Then use like this:
struct MyStruct {
public int Value1;
public int Value2;
//.. blah blah blah
}
byte[] bytes = ConvertToBytes(new MyStruct());
I've come up with a different approach that could convert any struct
without the hassle of fixing length, however the resulting byte array would have a little bit more overhead.
Here is a sample struct
:
[StructLayout(LayoutKind.Sequential)]
public class HelloWorld
{
public MyEnum enumvalue;
public string reqtimestamp;
public string resptimestamp;
public string message;
public byte[] rawresp;
}
As you can see, all those structures would require adding the fixed length attributes. Which could often ended up taking up more space than required. Note that the LayoutKind.Sequential
is required, as we want reflection to always gives us the same order when pulling for FieldInfo
. My inspiration is from TLV
Type-Length-Value. Let's have a look at the code:
public static byte[] StructToByteArray<T>(T obj)
{
using (MemoryStream ms = new MemoryStream())
{
FieldInfo[] infos = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (FieldInfo info in infos)
{
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream inms = new MemoryStream()) {
bf.Serialize(inms, info.GetValue(obj));
byte[] ba = inms.ToArray();
// for length
ms.Write(BitConverter.GetBytes(ba.Length), 0, sizeof(int));
// for value
ms.Write(ba, 0, ba.Length);
}
}
return ms.ToArray();
}
}
The above function simply uses the BinaryFormatter
to serialize the unknown size raw object
, and I simply keep track of the size as well and store it inside the output MemoryStream
too.
public static void ByteArrayToStruct<T>(byte[] data, out T output)
{
output = (T) Activator.CreateInstance(typeof(T), null);
using (MemoryStream ms = new MemoryStream(data))
{
byte[] ba = null;
FieldInfo[] infos = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (FieldInfo info in infos)
{
// for length
ba = new byte[sizeof(int)];
ms.Read(ba, 0, sizeof(int));
// for value
int sz = BitConverter.ToInt32(ba, 0);
ba = new byte[sz];
ms.Read(ba, 0, sz);
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream inms = new MemoryStream(ba))
{
info.SetValue(output, bf.Deserialize(inms));
}
}
}
}
When we want to convert it back to its original struct
we simply read the length back and directly dump it back into the BinaryFormatter
which in turn dump it back into the struct
.
These 2 functions are generic and should work with any struct
, I've tested the above code in my C#
project where I have a server and a client, connected and communicate via NamedPipeStream
and I forward my struct
as byte array from one and to another and converted it back.
I believe my approach might be better, since it doesn't fix length on the struct
itself and the only overhead is just an int
for every fields you have in your struct. There are also some tiny bit overhead inside the byte array generated by BinaryFormatter
, but other than that, is not much.