I've read several topics about but I still can't understand the real limitation of not being able to convert this structure to byte array easily:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct B {
public int b_a;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct A {
public int sizeB;
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
public B[] b;
}
I'm writing a TCP communication program so I want to build my S2C packets in a struct and then send them as byte[] so I'm looking for the cheapest and fastest way to achieve this.
I have already tried Marsheling in many ways but there is always some exception in Marshal.SizeOf().
In this example I get the following error: "[...] cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed."
Struct initialization eg.:
A a = new A();
B[] b = new B[5];
a.sizeB = 5;
a.b = b;
Marshal.SizeOf(a);
You don't have the same control for low level memory access like you would C or C++. You will need to do some manual work when you have an array of undefined length in C#.
Here are a couple ways of accomplishing that.
struct B
{
public int b_a;
}
struct A
{
public int sizeB;
public B[] b;
}
The first being a BinaryWriter. This can be faster if your structure does not have a lot of fields.
static byte[] ConvertToByte(A a)
{
using (var ms = new MemoryStream())
using (var writer = new BinaryWriter(ms))
{
writer.Write(a.sizeB);
foreach (var b in a.b)
writer.Write(b.b_a);
return ms.ToArray();
}
}
The other to use marshalling like you were but explicitly looping through the array.
static byte[] ConvertToByte(A a)
{
var bStructSize = Marshal.SizeOf<B>();
var size = bStructSize * a.b.Length;
var arr = new byte[size + 4];
var ptr = Marshal.AllocHGlobal(size);
for (int i = 0; i < a.b.Length; i++)
Marshal.StructureToPtr(a.b[i], ptr + i * bStructSize, true);
Marshal.Copy(ptr, arr, 4, size);
Array.Copy(BitConverter.GetBytes(a.sizeB), arr, 4);
return arr;
}