Struct Serialization using Unsafe Field I want to use structs as a container for data packets for asynchronous networking in C#. Found out that you can create a union style struct without the need to mark the struct itself as unsafe--instead marking the field as unsafe.
Example:
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Size = 8, Pack = 4)]
struct DataPacketStruct {
    private unsafe fixed byte bytes[8];
    // Publicly accessible fields.
    public byte header;
    public int size;
    
    public void Serialize(ref byte[] buffer, int startIndex) {
        unsafe {
            for (int i = 0; i &lt; 8; i++) buffer[startIndex + i] = bytes[i];
        }
    }

    public void Deserialize(byte[] buffer) {
        unsafe {
            for (int i = 0; i &lt; 8; i++) bytes[i] = buffer[i];
        }
    }
    
    public int SizeOf() { unsafe { return sizeof(DataPacketStruct); } }
}

I know I need array out of bounds checking--but apart from that. Potential downsides or undefined behaviors? Or is this usage valid? Also are there any potential performance concerns or any alternatives with similar performance?
Also an issue I can see right off the bat is not having compile-time numeric constants like in C++. Unfortunately have to hard code in the field offsets and structure size because of this: Size = 8 and byte[8].
There's a safe way to do that using System.Runtime.InteropServices.Marshal (link).
[StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)]
struct DataPacketStruct
{
    public byte Header { get; set; }
    public int Size { get; set; }

    public void Serialize(byte[] buffer, int startIndex)
    {
        int size = SizeOf();
        IntPtr ptr = Marshal.AllocHGlobal(size);
        Marshal.StructureToPtr(this, ptr, true);
        Marshal.Copy(ptr, buffer, startIndex, size);
        Marshal.FreeHGlobal(ptr);
    }

    public static DataPacketStruct Deserialize(byte[] buffer, int startIndex)
    {
        var result = new DataPacketStruct();
        int size = result.SizeOf();
        IntPtr ptr = Marshal.AllocHGlobal(size);
        Marshal.Copy(buffer, startIndex, ptr, size);
        result = (DataPacketStruct)Marshal.PtrToStructure(ptr, typeof(DataPacketStruct));
        Marshal.FreeHGlobal(ptr);
        return result;
    }

    public int SizeOf() =&gt; Marshal.SizeOf(this);
}

Also I used public properties and followed the Naming Guidelines in the example.
static void Main(string[] args)
{
    var data = new DataPacketStruct() { Header = byte.MaxValue, Size = int.MaxValue };
    byte[] a = new byte[8];
    data.Serialize(a, 0);
    Console.WriteLine(string.Join(&quot; &quot;, a.Select(x =&gt; x.ToString(&quot;X2&quot;))));
    var data2 = DataPacketStruct.Deserialize(a, 0);
    Console.WriteLine(JsonSerializer.Serialize(data2, new JsonSerializerOptions { WriteIndented = true }));
    Console.ReadKey();
}

Output:
FF 00 00 00 FF FF FF 7F
{
  &quot;Header&quot;: 255,
  &quot;Size&quot;: 2147483647
}