将byte []转换为显式结构的最简单方法

时间:2018-05-29 15:11:02

标签: c# struct unsafe

我正在寻找将byte []转换为struct的最简单方法。我的测试表明这有效:

[StructLayout(LayoutKind.Explicit, Size = OrderStruct.SIZE)]
public unsafe struct OrderStruct
{
    public const int SIZE = 16;

    [FieldOffset(0)]
    private fixed byte _data[OrderStruct.SIZE];

    [FieldOffset(0), MarshalAs(UnmanagedType.I4)]
    public int AssetId;

    [FieldOffset(4), MarshalAs(UnmanagedType.I4)]
    public int OrderQty;

    [FieldOffset(8), MarshalAs(UnmanagedType.R8)]
    public double Price;

    public static OrderStruct FromBytes(ref byte[] data)
    {
        if (data.Length < SIZE)
            throw new ArgumentException("Size is incorrect");

        OrderStruct t = default(OrderStruct);

        fixed (byte* src = data)
        {
            Buffer.MemoryCopy(src, t._data, SIZE, SIZE);
        }

        return t;
    }

    public byte[] ToBytes()
    {
        var result = new byte[SIZE];

        fixed (byte* dst = result)
        fixed (byte* src = this._data)
        {
            Buffer.MemoryCopy(src, dst, result.Length, SIZE);
        }
        return result;
    }
}

我错过了一个边缘案例,或者这是解决这个问题的好方法吗?

其他信息:

  • 性能很重要,否则我只会使用BitConverter单独转换每个项目,这个解决方案显然更快。
  • 我真的不需要通用解决方案,因为我只会在代码库中为1或2个项目执行此操作。
  • 在我的情况下,我不需要担心字节序,因为这已经在其他地方处理了。

1 个答案:

答案 0 :(得分:0)

这将有效,没有不安全的代码(但事实上它仍然非常不安全)...... try... finally...try {}用于防止异步异常。

public struct OrderStruct
{
    public const int SIZE = 16;

    public int AssetId;
    public int OrderQty;
    public double Price;

    public static OrderStruct FromBytes(byte[] data)
    {
        if (data.Length < SIZE)
            throw new ArgumentException("Size is incorrect");

        GCHandle h = default(GCHandle);

        try
        {
            try
            {

            }
            finally
            {
                h = GCHandle.Alloc(data, GCHandleType.Pinned);
            }

            OrderStruct t = Marshal.PtrToStructure<OrderStruct>(h.AddrOfPinnedObject());
            return t;
        }
        finally
        {
            if (h.IsAllocated)
            {
                h.Free();
            }
        }
    }

    public byte[] ToBytes()
    {
        var result = new byte[SIZE];

        GCHandle h = default(GCHandle);

        try
        {
            try
            {

            }
            finally
            {
                h = GCHandle.Alloc(result, GCHandleType.Pinned);
            }

            Marshal.StructureToPtr(this, h.AddrOfPinnedObject(), false);
            return result;
        }
        finally
        {
            if (h.IsAllocated)
            {
                h.Free();
            }
        }
    }
}