C#中结构体和字节数组转换

方式一

 通过Marshal实现结构体和字节数组之间的转换。

using System;
using System.Runtime.InteropServices;

namespace MarshalSample
{
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    struct Message
    {
        public ushort begin;
        [MarshalAs(UnmanagedType.U1)]
        public bool result;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public byte[] detail;
        public ushort end;
    };

    class Program
    {
        public static byte[] StructToBytes<T>(T obj)
        {
            int size = Marshal.SizeOf<T>();
            byte[] bytes = new byte[size];
            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(obj, ptr, false);
            Marshal.Copy(ptr, bytes, 0, size);
            Marshal.FreeHGlobal(ptr);

            return bytes;
        }

        public static T BytesToStruct<T>(byte[] bytes)
        {
            int size = Marshal.SizeOf<T>();
            if (bytes.Length < size)
            {
                return default(T);
            }

            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.Copy(bytes, 0, ptr, size);
            T obj = Marshal.PtrToStructure<T>(ptr);
            Marshal.FreeHGlobal(ptr);

            return obj;
        }

        static void Main(string[] args)
        {
            Message msg;
            msg.begin = 0xF9F9;
            msg.result = true;
            msg.detail = new byte[2] { 0x00, 0x00 };
            msg.end = 0x9F9F;

            byte[] bytes = StructToBytes(msg);
            Message newMsg = BytesToStruct<Message>(bytes);
        }
    }
}

方式二

通过MemoryMarshal实现结构体和字节数组之间的转换。

using System;
using System.Runtime.InteropServices;

namespace MarshalSample
{
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    struct Message
    {
        public ushort begin;
        [MarshalAs(UnmanagedType.U1)]
        public bool result;
        //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        //public byte[] detail;
        public ushort end;
    };

    class Program
    {
        public static byte[] StructToBytes<T>(T obj) where T : struct
        {
            int size = Marshal.SizeOf<T>();
            byte[] bytes = new byte[size];

            T value = (T)obj;
            MemoryMarshal.Write<T>(bytes.AsSpan(), ref value);

            return bytes;
        }

        public static T BytesToStruct<T>(byte[] bytes) where T : struct
        {
            int size = Marshal.SizeOf<T>();
            if (bytes.Length < size)
            {
                return default(T);
            }

            var obj = MemoryMarshal.Read<T>(bytes);

            return obj;
        }

        static void Main(string[] args)
        {
            Message msg;
            msg.begin = 0xF9F9;
            msg.result = true;
            //msg.detail = new byte[2] { 0x00, 0x00 };
            msg.end = 0x9F9F;

            byte[] bytes = StructToBytes(msg);
            Message newMsg = BytesToStruct<Message>(bytes);
        }
    }
}

MemoryMarshal的使用有限制,结构体中不能包含指针和引用。如果打开代码中的注释后,运行时会抛出异常。详细见Microsoft文档中的说明:

public static T Read<T> (ReadOnlySpan<byte> source) where T : struct;
public static void Write<T> (Span<byte> destination, ref T value) where T : struct;

Remarks
T cannot contain pointers or references. It is checked at runtime in order to preserve type safety.

参考:

C#中结构体定义并转换字节数组 - bigfan - 博客园

C#结构体使用bool类型,并使其长度为1_sdhongjun的专栏-CSDN博客

C# Marshal.SizeOf和sizeof的区别_Sakuya__的博客-CSDN博客_c# marshal.sizeof


版权声明:本文为yonglixiangban原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。