将非常量大小的结构转换为字节数组

时间:2017-05-18 13:29:16

标签: c# arrays struct marshalling data-conversion

我正在开发一个通过µControllerUDP-Messages进行通信的图书馆。为此,我使用的是一个自定义协议,它基本上是一个由2个元素组成的结构:标题(一些元数据+校验和)和有效负载。 通过System.Net.Sockets.UDPClient类完成通信。要转换我的数据,我使用以下函数:

private List<byte> GetBytes(object str)
{
    int size = Marshal.SizeOf(str);
    byte[] arr = new byte[size];
    IntPtr ptr = Marshal.AllocHGlobal(size);
    Marshal.StructureToPtr(str, ptr, true);
    Marshal.Copy(ptr, arr, 0, size);
    Marshal.FreeHGlobal(ptr);
    return arr.ToList();
}

如果我想发送一些不是常量大小的有效负载,我现在遇到问题,例如,如果我只想向μController写一些可变长度的数据。我目前使用的一种解决方法是将我的有效负载封装在一个常量(最大)大小的结构中,但这对我来说似乎不是很有效。

那么,有没有办法将非常量大小的结构转换为带有C#的字节数组?例如这个结构:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct PERIPHERY__PROTOCOL
{
    public PERIPHERY_HEADER strHeader;       
    public byte[] Data;
}

2 个答案:

答案 0 :(得分:1)

在您的PERIPHERY__PROTOCOL示例中,您实际上并未将数据放入结构中 - 您正在创建单独的数组并将数据放在那里。你仍然可以做到这一点,绝对 - 但你必须支付堆开销。在这种情况下,忘记Marshal - 您只需传递 arr 到结构

但如果你的意思是“我可以在.NET中使用可变长度的结构”;不 - 不,你不能。

答案 1 :(得分:1)

为什么要使用结构?

使用课程。此示例代码允许您添加新的数据包类型并将其转换为字节。如果你想要将它转换回来的机制(从字节到类),你需要添加自己的发明。

public abstract class Packet
{
    public int PacketType { get; }

    public Packet (int packetType)
    {
        PacketType = packetType;
    }

    protected abstract byte[] GetPayload ();

    private int CalculateChecksum ()
    {
        byte[] packetTypeBytes = BitConverter.GetBytes (PacketType);
        byte[] payloadBytes    = GetPayload ();
        byte[] lengthBytes     = BitConverter.GetBytes (payloadBytes.Length);

        return 0; // add some logic to calculate checksum from all bytes
    }

    public byte[] ToBytes ()
    {
        byte[] packetTypeBytes = BitConverter.GetBytes (PacketType);
        byte[] checksumBytes   = BitConverter.GetBytes (CalculateChecksum ());
        byte[] payloadBytes    = GetPayload ();
        byte[] lengthBytes     = BitConverter.GetBytes (payloadBytes.Length);

        return packetTypeBytes.Concat (lengthBytes).Concat (checksumBytes).Concat (payloadBytes).ToArray ();

    }
}



public sealed class ActionA : Packet
{
    public string Message { get; }

    public ActionA (string message) : base (0)
    {
        Message = message;
    }

    protected override byte[] GetPayload ()
    {
        return Encoding.ASCII.GetBytes (Message);
    }


}



public sealed class ActionB : Packet
{
    public int Value { get; }

    public ActionB (int value) : base (1)
    {
        Value = value;
    }

    protected override byte[] GetPayload ()
    {
        return BitConverter.GetBytes (Value);
    }
}