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

本文介绍了两种在C#中进行结构体和字节数组转换的方法:一是利用Marshal,二是使用MemoryMarshal。MemoryMarshal的使用需要注意结构体不能包含指针和引用,否则会导致运行时异常。参考了优快云博主的文章,详细探讨了转换过程及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

方式一

 通过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的专栏-优快云博客

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值