今天遇到有人提到结构体和byte数组互转的问题,我就顺便拿来水一篇。这是一个冷门的问题,估计使用的人不多。既然有需求,应该就有使用场景,那就顺便整一波。
为了达到效果,结构体、复杂结构体嵌套等都能实现转换,我就顺便做了个包更新来提供使用和下面的说明。
首先引入nuget包 Wesky.Net.OpenTools 的最新版
 
新建几个结构体做实验。结构体结构如下所示,做四个层级的嵌套,包括数组、基础类型、结构体数组和嵌套等。
 
使用方式:
对结构体属性进行赋值等操作,模拟一个我们要做的对象数据。
实例化一个转换器
转换器选择方式有两种,一种针对基础类型的操作,用Marshal自带的方法进行实现。另一种为复杂类型的转换实现。此处主要演示第二种(上面结构体会自动选择第二种转换器)
转换器选择内部实现源码如下:
 1 /// <summary>
2 /// 提供结构体转换器的工厂类。
3 /// Provides a factory class for structure converters.
4 /// </summary>
5 public class StructConvertFactory
6 {
7 /// <summary>
8 /// 根据结构体类型的复杂性选择合适的转换器。
9 /// Selects an appropriate converter based on the complexity of the structure type.
10 /// </summary>
11 /// <typeparam name="T">要为其创建转换器的结构体类型。</typeparam>
12 /// <returns>返回符合结构体类型特性的转换器实例。</returns>
13 /// <remarks>
14 /// 如果结构体包含复杂字段,则返回一个基于反射的转换器,否则返回一个基于内存操作的转换器。
15 /// If the structure contains complex fields, a reflection-based converter is returned; otherwise, a memory operation-based converter is provided.
16 /// </remarks>
17 public static IStructConvert CreateConvertor<T>() where T : struct
18 {
19 // 判断结构体类型T是否包含复杂字段
20 if (HasComplexFields(typeof(T)))
21 {
22 // 返回反射方式实现的结构体转换器
23 return new StructConvert();
24 }
25 else
26 {
27 // 返回Marshal自带的操作方式实现的结构体转换器
28 return new MarshalConvert();
29 }
30 }
31
32 /// <summary>
33 /// 验证指定类型的字段是否包含复杂类型。
34 /// Verifies whether the fields of the specified type contain complex types.
35 /// </summary>
36 /// <param name="type">要检查的类型。</param>
37 /// <returns>如果包含复杂类型字段,则返回true;否则返回false。</returns>
38 /// <remarks>
39 /// 复杂类型包括数组、类以及非基本的值类型(如结构体),但不包括decimal。
40 /// Complex types include arrays, classes, and non-primitive value types such as structures, but exclude decimal.
41 /// </remarks>
42 private static bool HasComplexFields(Type type)
43 {
44 foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Instance))
45 {
46 if (field.FieldType.IsArray || field.FieldType.IsClass ||
47 (field.FieldType.IsValueType && !field.FieldType.IsPrimitive &&
48 field.FieldType != typeof(decimal)))
49 {
50 return true;
51 }
52 }
53 return false;
54 }
55 }
转换器都继承自IStructConvert接口,IStructConvert接口定义如下
 1 /// <summary>
2 /// IStructConvert 接口,提供结构体与字节数组之间的序列化和反序列化功能。
3 /// IStructConvert interface, providing serialization and deserialization functionality between structures and byte arrays.
4 /// </summary>
5 public interface IStructConvert
6 {
7 /// <summary>
8 /// 将字节数组反序列化为结构体。
9 /// Deserializes a byte array into a structure.
10 /// </summary>
11 /// <typeparam name="T">结构体的类型。</typeparam>
12 /// <param name="data">包含结构体数据的字节数组。</param>
13 /// <returns>反序列化后的结构体实例。</returns>
14 byte[] StructToBytes<T>(T structure) where T : struct;
15
16 /// <summary>
17 /// 将结构体实例转换为字节数组。
18 /// Converts a structure instance into a byte array.
19 /// </summary>
20 /// <typeparam name="T">要转换的结构体类型,必须是值类型。</typeparam>
21 /// <param name="structure">要转换的结构体实例。</param>
22 /// <returns>表示结构体数据的字节数组。</returns>
23 T BytesToStruct<T>(byte[] data) where T : struct;
24 }
所以下面我们可以直接调用转换器的这两个方法来实现数据的转换:
设置断点,执行程序。监视到byte数组的data数据有77个元素
继续监控数组数据转换回来的数据,可以对比到对象的数据和上面定义的内容是一致的,说明数据转换成功。
其他核心代码——MarshalConvert类转换器代码:
 1   /// <summary>
2 /// 实现IStructConvert接口,提供结构体与字节数组间的基本转换功能。
3 /// Implements the IStructConvert interface to provide conversion between structures and byte arrays.
4 /// </summary>
5 public class MarshalConvert : IStructConvert
6 {
7 /// <summary>
8 /// 将字节数组转换为指定类型的结构体实例。
9 /// Converts a byte array into an instance of the specified type of structure.
10 /// </summary>
11 /// <typeparam name="T">要转换的结构体类型,必须是值类型。</typeparam>
12 /// <param name="data">包含结构体数据的字节数组。</param>
13 /// <returns>转换后的结构体实例。</returns>
14 public T BytesToStruct<T>(byte[] data) where T : struct
15 {
16 T structure;
17 // 计算结构体类型T的内存大小
18 // Calculate the memory size of the structure type T
19 int size = Marshal.SizeOf(typeof(T));
20 // 分配相应大小的内存缓冲区
21 // Allocate a memory buffer of the appropriate size
22 IntPtr buffer = Marshal.AllocHGlobal(size);
23 try
24 {
25 // 将字节数组复制到分配的内存中
26 // Copy the byte array to the allocated memory
27 Marshal.Copy(data, 0, buffer, size);
28 // 将内存缓冲区转换为指定的结构体
29 // Convert the memory buffer to the specified structure
30 structure = Marshal.PtrToStructure<T>(buffer);
31 }
32 finally
33 {
34 // 释放内存缓冲区
35 // Free the memory buffer
36 Marshal.FreeHGlobal(buffer);
37 }
38 return structure;
39 }
40
41 /// <summary>
42 /// 将结构体实例转换为字节数组。
43 /// Converts a structure instance into a byte array.
44 /// </summary>
45 /// <typeparam name="T">要转换的结构体类型,必须是值类型。</typeparam>
46 /// <param name="structure">要转换的结构体实例。</param>
47 /// <returns>表示结构体数据的字节数组。</returns>
48 public byte[] StructToBytes<T>(T structure) where T : struct
49 {
50 // 计算结构体实例的内存大小
51 // Calculate the memory size of the structure instance
52 int size = Marshal.SizeOf(structure);
53 byte[] array = new byte[size];
54 // 分配相应大小的内存缓冲区
55 // Allocate a memory buffer of the appropriate size
56 IntPtr buffer = Marshal.AllocHGlobal(size);
57 try
58 {
59 // 将结构体实例复制到内存缓冲区
60 // Copy the structure instance to the memory buffer
61 Marshal.StructureToPtr(structure, buffer, false);
62 // 将内存缓冲区的数据复制到字节数组
63 // Copy the data from the memory buffer to the byte array
64 Marshal.Copy(buffer, array, 0, size);
65 }
66 finally
67 {
68 // 释放内存缓冲区
69 // Free the memory buffer
70 Marshal.FreeHGlobal(buffer);
71 }
72 return array;
73 }
74 }
如果以上内容对你有帮助,欢迎点赞、转发、在看和关注我的个人公众号:【Dotnet Dancer
如果需要以上演示代码,可以在公众号【Dotnet Dancer】后台回复“结构体转换”进行获取。
OpenTools系列文章快捷链接【新版本完全兼容旧版本,不需要更新任何代码均可使用】:
1.0.13版本
快速实现.NET(.net framework/.net core+)动态访问webservice服务
1.0.11版本
如何一行C#代码实现解析类型的Summary注释(可用于数据字典快速生成)
1.0.10版本:
C#/.NET一行代码把实体类类型转换为Json数据字符串
1.0.8版本:
上位机和工控必备!用.NET快速搞定Modbus通信的方法
1.0.7版本:
大揭秘!.Net如何在5分钟内快速实现物联网扫码器通用扫码功能?
1.0.6版本:
.NET实现获取NTP服务器时间并同步(附带Windows系统启用NTP服务功能)
1.0.5版本:
C#使用P/Invoke来实现注册表的增删改查功能
1.0.3版本:
C#实现图片转Base64字符串,以及base64字符串在Markdown文件内复原的演示
1.0.2版本:
​C#实现Ping远程主机功能(支持IP和域名)
1.0.1版本:
开始开源项目OpenTools的创作(第一个功能:AES加密解密)
 
【备注】包版本完全开源,并且没有任何第三方依赖。使用.net framework 4.6+、任意其他跨平台.net版本环境,均可直接引用。

使用Wesky.Net.OpenTools包来快速实现嵌套型结构体数据转换功能的更多相关文章

  1. CentOS6.8 RPM包安装快速zabbix22

    CentOS6.8 RPM包安装快速zabbix22 yum install -y epel-release # yum install -y httpd php php-devel mysql-se ...

  2. oracle函数、包、变量的定义和使用、重点”结构体和数组”

    函数 实例1:输入雇员的姓名,返回该雇员的年薪 create function fun1(spName varchar2) ,); begin +nvl(comm,) into yearSal fro ...

  3. C数组&结构体&联合体快速初始化

    背景 C89标准规定初始化语句的元素以固定顺序出现,该顺序即待初始化数组或结构体元素的定义顺序. C99标准新增指定初始化(Designated Initializer),即可按照任意顺序对数组某些元 ...

  4. 利用flask-sqlacodegen快速导入ORM表结构

    利用flask-sqlacodegen快速导入ORM表结构 友情提示:如果是使用pymysql请预先pip install 哦~ 这是window下使用virtualenv环境下执行的 Linux用户 ...

  5. TCP/IP各种数据包结构体

    下面这些TCP/IP数据包是我在进行Socket及Wipcap网络编程过程中曾经用到过的数据包结构体, 这些东西平时看起来不起眼,真正用到的时候就会觉得非常有用...... 以太帧头格式结构体,共14 ...

  6. mtools 是由MongoDB 官方工程师实现的一套工具集,可以很快速的日志查询分析、统计功能,此外还支持本地集群部署管理.

    mtools 是由MongoDB 官方工程师实现的一套工具集,可以很快速的日志查询分析.统计功能,此外还支持本地集群部署管理 https://www.cnblogs.com/littleatp/p/9 ...

  7. Go语言学习笔记(8)——包和结构体

    包 —— 每个可执行的应用程序必须包含一个主函数,它是执行的入口点.主函数应该存在main包中. 结构体: 通过 . 操作符访问结构体的各个成员! 1. 定义结构体类型person: type per ...

  8. struct2json -- C结构体与 JSON 快速互转库V1.0发布

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/zhutianlong/article/d ...

  9. C89,C99: C数组&结构体&联合体快速初始化

    1. 背景 C89标准规定初始化语句的元素以固定顺序出现,该顺序即待初始化数组或结构体元素的定义顺序. C99标准新增指定初始化(Designated Initializer),即可按照任意顺序对数组 ...

  10. Win10如何设置休眠选项(关于睡眠、休眠、快速启动这几个伪关机功能如何设置更适合笔记本电脑?)

    · Win10如何设置休眠选项(关于睡眠.休眠.快速启动这几个伪关机功能如何设置更适合笔记本电脑?) 应用场景 升级正式版win10以后,发现竟然没有休眠选项,从电源管理器里面也没有找到,有时候有些重 ...

随机推荐

  1. Apsara Stack 同行者专刊 | 怀同行之心,筑信任之基,践数智之行

    简介: 政企云平台处在怎样的历史阶段?数智创新的同行者们面临着怎样的挑战与机遇?在时代巨幕下,政企期待云厂商扮演怎样的角色?阿里云智能研究员.混合云平台总经理刘国华认为,云厂商不仅需要有定力与实力,也 ...

  2. 阿里云发布第四代神龙架构,提供业界首个大规模弹性RDMA加速能力

    ​简介:10月20日,2021年杭州云栖大会上,阿里云发布第四代神龙架构,升级至全新的eRMDA网络架构,是业界首个大规模弹性RDMA加速能力. 10月20日,2021年杭州云栖大会上,阿里云发布第四 ...

  3. 【详谈 Delta Lake 】系列技术专题 之 特性(Features)

    简介: 本文翻译自大数据技术公司 Databricks 针对数据湖 Delta Lake 的系列技术文章.众所周知,Databricks 主导着开源大数据社区 Apache Spark.Delta L ...

  4. [FAQ] FinalCutPro 视频背景加模糊效果

    1. 时间轴右上方,找到 倒数第二个 "显示或隐藏效果浏览器",里面有一个 "模糊" 效果: 2. "模糊"效果中的 "高斯曲线& ...

  5. PostMan测试图片上传接口的方法

    一.选择POST后添加接口地址 二.选择Body下的from-data 注:Headers不要加参数 三.填写key,再key后的下拉选择file,然后选择文件 注:key并不是图片名称,而是接口接收 ...

  6. ES_CCS/R(二):跨集群搜索 Cross-cluster search (CCS)

    跨集群搜索(cross-cluster search)使你可以针对一个或多个远程集群运行单个搜索请求. 例如,你可以使用跨集群搜索来筛选和分析存储在不同数据中心的集群中的日志数据. 示例 :在一个集群 ...

  7. Spire.Doc 生成长图

    按模板生成内容,转换成长图保存: Document doc = new Document("A_BizRpt.docx"); ....... Image[] imgs = doc. ...

  8. 【Python基础】两个参数的for循环步长写法

    一个参数for循环步长写法 >>> for i in range(1,10000,1000):print(i) ... 1 1001 2001 3001 4001 5001 6001 ...

  9. salesforce零基础学习(一百三十六)零碎知识点小总结(八)

    本篇参考: Salesforce LWC学习(七) Navigation & Toast https://developer.salesforce.com/docs/platform/lwc/ ...

  10. JDK源码阅读-------自学笔记(十八)(java.lang.Enum枚举类)

    枚举类简介 如果有必要定义一组常量的时候使用 所有的枚举类型隐性地继承自 java.lang.Enum,枚举实质上还是类. 每一个枚举中的成员,就相当于枚举的一个对象,默认都是public stati ...