Have you tried your first approach with an struct that contains an array? That won't work because Marshal.SizeOf
will return the size of the pointer to the int-array (x86=4, x64=8) and not the length of the int-array...
I don't know for sure how an array will be written to a byte array in C. But I assume the following:
new int[] { 10,11,12 }
should result in a 12 byte long byte-array: four bytes for the length and three times four bytes for each array-item. So on a little-endian-system it would look like
new byte[] { 3,0,0,0, 10,0,0,0, 11,0,0,0, 12,0,0,0 }
.
I also don't know how this have to look on a big-endian system, but I assume that only the byte-blocks have to be reversed and not the order. So fo a big endian system it could like
new byte[] { 0,0,0,3, 0,0,0,10, 0,0,0,11, 0,0,0,12 }
.
or, if the order of the items also has to be reversed, it might look like
new byte[] { 0,0,0,3, 0,0,0,12, 0,0,0,11, 0,0,0,10 }
.
public static byte[] StructToArray<T>(T obj)
{
var size = Marshal.SizeOf(obj);
var mem = new MemoryStream(size);
var fields = obj.GetType().GetFields();
var little = BitConverter.IsLittleEndian;
foreach(var field in fields)
{
var val = field.GetValue(obj);
var type = val.GetType();
if(type == typeof(int))
{
var raw = BitConverter.GetBytes((int)val);
if (little) raw = raw.Reverse().ToArray();
mem.Write(raw, 0, raw.Length);
}
else if(type == typeof(int[]))
{
var array = (int[])val;
var length = BitConverter.GetBytes(array.Length);
if (little) length = length.Reverse().ToArray();
var raw = array.Select(x => BitConverter.GetBytes(x)).ToList();
if (little) raw = raw.Select(x => x.Reverse().ToArray()).ToList();
// Write the length...
mem.Write(length, 0, length.Length);
// ...and the items in "normal" order
for (int i = 0; i < raw.Count; i++)
mem.Write(raw[i], 0, raw[i].Length);
}
}
return mem.ToArray();
}
Also keep in mind that the MSDN page of .GetFields()
contains the following notice:
The GetFields method does not return fields in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which fields are returned, because that order varies.
Thats the reason why you should use an attribute to define the order and not to rely on the coincidence that the the framework version you're using returns them in declaration order.