方式一
通过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