经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
使用Wesky.Net.OpenTools包来快速实现嵌套型结构体数据转换功能
来源:cnblogs  作者:WeskyNet  时间:2024/6/12 21:17:39  对本文有异议
今天遇到有人提到结构体和byte数组互转的问题,我就顺便拿来水一篇。这是一个冷门的问题,估计使用的人不多。既然有需求,应该就有使用场景,那就顺便整一波。
为了达到效果,结构体、复杂结构体嵌套等都能实现转换,我就顺便做了个包更新来提供使用和下面的说明。
首先引入nuget包 Wesky.Net.OpenTools 的最新版
0
 
新建几个结构体做实验。结构体结构如下所示,做四个层级的嵌套,包括数组、基础类型、结构体数组和嵌套等。
0
 
使用方式:
对结构体属性进行赋值等操作,模拟一个我们要做的对象数据。
0
实例化一个转换器
0
转换器选择方式有两种,一种针对基础类型的操作,用Marshal自带的方法进行实现。另一种为复杂类型的转换实现。此处主要演示第二种(上面结构体会自动选择第二种转换器)
转换器选择内部实现源码如下:
  1. 1 /// <summary>
  2. 2 /// 提供结构体转换器的工厂类。
  3. 3 /// Provides a factory class for structure converters.
  4. 4 /// </summary>
  5. 5 public class StructConvertFactory
  6. 6 {
  7. 7 /// <summary>
  8. 8 /// 根据结构体类型的复杂性选择合适的转换器。
  9. 9 /// Selects an appropriate converter based on the complexity of the structure type.
  10. 10 /// </summary>
  11. 11 /// <typeparam name="T">要为其创建转换器的结构体类型。</typeparam>
  12. 12 /// <returns>返回符合结构体类型特性的转换器实例。</returns>
  13. 13 /// <remarks>
  14. 14 /// 如果结构体包含复杂字段,则返回一个基于反射的转换器,否则返回一个基于内存操作的转换器。
  15. 15 /// If the structure contains complex fields, a reflection-based converter is returned; otherwise, a memory operation-based converter is provided.
  16. 16 /// </remarks>
  17. 17 public static IStructConvert CreateConvertor<T>() where T : struct
  18. 18 {
  19. 19 // 判断结构体类型T是否包含复杂字段
  20. 20 if (HasComplexFields(typeof(T)))
  21. 21 {
  22. 22 // 返回反射方式实现的结构体转换器
  23. 23 return new StructConvert();
  24. 24 }
  25. 25 else
  26. 26 {
  27. 27 // 返回Marshal自带的操作方式实现的结构体转换器
  28. 28 return new MarshalConvert();
  29. 29 }
  30. 30 }
  31. 31
  32. 32 /// <summary>
  33. 33 /// 验证指定类型的字段是否包含复杂类型。
  34. 34 /// Verifies whether the fields of the specified type contain complex types.
  35. 35 /// </summary>
  36. 36 /// <param name="type">要检查的类型。</param>
  37. 37 /// <returns>如果包含复杂类型字段,则返回true;否则返回false。</returns>
  38. 38 /// <remarks>
  39. 39 /// 复杂类型包括数组、类以及非基本的值类型(如结构体),但不包括decimal。
  40. 40 /// Complex types include arrays, classes, and non-primitive value types such as structures, but exclude decimal.
  41. 41 /// </remarks>
  42. 42 private static bool HasComplexFields(Type type)
  43. 43 {
  44. 44 foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Instance))
  45. 45 {
  46. 46 if (field.FieldType.IsArray || field.FieldType.IsClass ||
  47. 47 (field.FieldType.IsValueType && !field.FieldType.IsPrimitive &&
  48. 48 field.FieldType != typeof(decimal)))
  49. 49 {
  50. 50 return true;
  51. 51 }
  52. 52 }
  53. 53 return false;
  54. 54 }
  55. 55 }

 

转换器都继承自IStructConvert接口,IStructConvert接口定义如下
  1. 1 /// <summary>
  2. 2 /// IStructConvert 接口,提供结构体与字节数组之间的序列化和反序列化功能。
  3. 3 /// IStructConvert interface, providing serialization and deserialization functionality between structures and byte arrays.
  4. 4 /// </summary>
  5. 5 public interface IStructConvert
  6. 6 {
  7. 7 /// <summary>
  8. 8 /// 将字节数组反序列化为结构体。
  9. 9 /// Deserializes a byte array into a structure.
  10. 10 /// </summary>
  11. 11 /// <typeparam name="T">结构体的类型。</typeparam>
  12. 12 /// <param name="data">包含结构体数据的字节数组。</param>
  13. 13 /// <returns>反序列化后的结构体实例。</returns>
  14. 14 byte[] StructToBytes<T>(T structure) where T : struct;
  15. 15
  16. 16 /// <summary>
  17. 17 /// 将结构体实例转换为字节数组。
  18. 18 /// Converts a structure instance into a byte array.
  19. 19 /// </summary>
  20. 20 /// <typeparam name="T">要转换的结构体类型,必须是值类型。</typeparam>
  21. 21 /// <param name="structure">要转换的结构体实例。</param>
  22. 22 /// <returns>表示结构体数据的字节数组。</returns>
  23. 23 T BytesToStruct<T>(byte[] data) where T : struct;
  24. 24 }

 

所以下面我们可以直接调用转换器的这两个方法来实现数据的转换:
0
设置断点,执行程序。监视到byte数组的data数据有77个元素
0
继续监控数组数据转换回来的数据,可以对比到对象的数据和上面定义的内容是一致的,说明数据转换成功。
0
其他核心代码——MarshalConvert类转换器代码:
  1. 1 /// <summary>
  2. 2 /// 实现IStructConvert接口,提供结构体与字节数组间的基本转换功能。
  3. 3 /// Implements the IStructConvert interface to provide conversion between structures and byte arrays.
  4. 4 /// </summary>
  5. 5 public class MarshalConvert : IStructConvert
  6. 6 {
  7. 7 /// <summary>
  8. 8 /// 将字节数组转换为指定类型的结构体实例。
  9. 9 /// Converts a byte array into an instance of the specified type of structure.
  10. 10 /// </summary>
  11. 11 /// <typeparam name="T">要转换的结构体类型,必须是值类型。</typeparam>
  12. 12 /// <param name="data">包含结构体数据的字节数组。</param>
  13. 13 /// <returns>转换后的结构体实例。</returns>
  14. 14 public T BytesToStruct<T>(byte[] data) where T : struct
  15. 15 {
  16. 16 T structure;
  17. 17 // 计算结构体类型T的内存大小
  18. 18 // Calculate the memory size of the structure type T
  19. 19 int size = Marshal.SizeOf(typeof(T));
  20. 20 // 分配相应大小的内存缓冲区
  21. 21 // Allocate a memory buffer of the appropriate size
  22. 22 IntPtr buffer = Marshal.AllocHGlobal(size);
  23. 23 try
  24. 24 {
  25. 25 // 将字节数组复制到分配的内存中
  26. 26 // Copy the byte array to the allocated memory
  27. 27 Marshal.Copy(data, 0, buffer, size);
  28. 28 // 将内存缓冲区转换为指定的结构体
  29. 29 // Convert the memory buffer to the specified structure
  30. 30 structure = Marshal.PtrToStructure<T>(buffer);
  31. 31 }
  32. 32 finally
  33. 33 {
  34. 34 // 释放内存缓冲区
  35. 35 // Free the memory buffer
  36. 36 Marshal.FreeHGlobal(buffer);
  37. 37 }
  38. 38 return structure;
  39. 39 }
  40. 40
  41. 41 /// <summary>
  42. 42 /// 将结构体实例转换为字节数组。
  43. 43 /// Converts a structure instance into a byte array.
  44. 44 /// </summary>
  45. 45 /// <typeparam name="T">要转换的结构体类型,必须是值类型。</typeparam>
  46. 46 /// <param name="structure">要转换的结构体实例。</param>
  47. 47 /// <returns>表示结构体数据的字节数组。</returns>
  48. 48 public byte[] StructToBytes<T>(T structure) where T : struct
  49. 49 {
  50. 50 // 计算结构体实例的内存大小
  51. 51 // Calculate the memory size of the structure instance
  52. 52 int size = Marshal.SizeOf(structure);
  53. 53 byte[] array = new byte[size];
  54. 54 // 分配相应大小的内存缓冲区
  55. 55 // Allocate a memory buffer of the appropriate size
  56. 56 IntPtr buffer = Marshal.AllocHGlobal(size);
  57. 57 try
  58. 58 {
  59. 59 // 将结构体实例复制到内存缓冲区
  60. 60 // Copy the structure instance to the memory buffer
  61. 61 Marshal.StructureToPtr(structure, buffer, false);
  62. 62 // 将内存缓冲区的数据复制到字节数组
  63. 63 // Copy the data from the memory buffer to the byte array
  64. 64 Marshal.Copy(buffer, array, 0, size);
  65. 65 }
  66. 66 finally
  67. 67 {
  68. 68 // 释放内存缓冲区
  69. 69 // Free the memory buffer
  70. 70 Marshal.FreeHGlobal(buffer);
  71. 71 }
  72. 72 return array;
  73. 73 }
  74. 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版本环境,均可直接引用。

原文链接:https://www.cnblogs.com/weskynet/p/18244720

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号