.NET 结构体
我们都知道结构体struct,在大量创建、引用的场景下相比类class能提升很大性能。本文介绍下如何正确使用struct
struct定义
1 struct Point 2 { 3 public float X; 4 public float Y; 5 } 6 7 class Rect 8 { 9 public Point Position; 10 } 11 12 Rect rect = new Rect();
上述代码中,rect的Position字段并没有分配到栈上,反而是和Rect的实例一起被分配到了托管堆中。除此之外,装箱也会导致结构体实例分配到托管堆:
1 Point point = new Point(); 2 object obj = point; // 装箱,结构体转移到托管堆
所以如果因为性能要求或者其它原因想限制struct只分配到栈上的话,可以添加ref:
1 ref struct Point 2 { 3 public float X; 4 public float Y; 5 }
这种情况下,struct关键字前添加ref是指将结构体声明为只能在栈上分配的结构体,对于这种结构体,任何可能将其转移到托管堆的行为都将被阻止(例如在引用类型中定义ref结构体字段,或者进行装箱操作):
1 class Rect 2 { 3 public Point Position; // 错误,Position会随着Rect实例转移到托管堆 4 } 5 6 Point point = new Point(); 7 object obj = point; // 错误,point会被装箱到托管堆
另外,ref声明的struct可以继续作为字段在新struct内声明:
1 ref struct PointNew 2 { 3 public Point Point; // 允许,因为XPoint同样保证了栈上分配 4 }
还可以声明只读的ref结构体:
1 readonly ref struct PointNew 2 { 3 public Point Point; // 允许,因为XPoint同样保证了栈上分配 4 }
使用struct
1. 结构体作为参数传递
1 Point p = new Point(); 2 TestAdd(ref p); 3 4 void TestAdd(ref Point point) 5 { 6 point.X += 1; 7 }
如果不是只传值而是需要变更数据,需要添加ref,否则TestAdd中point只会作为原来p的副本生成一个新结构体。那最终p中的X值还是初始值0。ref我们都熟悉了,值类型如果作为参数输入后,外部同步修改也是使用ref
2. 结构体存储大小
看下面这段代码,输出结构体在栈上所需的内存大小:
1 [StructLayout(LayoutKind.Auto)] 2 struct TestStorage 3 { 4 public byte A; 5 public int B; 6 public byte C; 7 public byte D; 8 public byte E; 9 } 10 // 输出 11 unsafe 12 { 13 Debug.WriteLine(sizeof(TestStorage)); 14 }
上面输出的值是12。我们聊下内存布局:
1)Sequential:顺序布局,按字段的声明顺序布局,是默认行为
2)Auto:自动布局,自动排列字段顺序以用最小的空间来储存字段
3)Explicit:显式布局,手动指定字段地址的偏移
一般来说,byte是1,int是4。
在不添加[StructLayout(LayoutKind.Auto)]标记时,由于需要内存对齐,字段B是4,那内存大小就需要以4+4+4=12来分配,前面4存储字段A 1的内存,后面4存储字段CDE一共3的内存大小
添加[StructLayout(LayoutKind.Auto)]后,内存对齐,只需要4+4=8的内存大小
我们使用Struct场景主要有以下使用场景:
- 一般是某类数据使用较多、有较大的内存问题 - 对于不需要频繁分配和释放的大量小对象,可以使用结构体减少堆内存的压力
- 现有类对象创建回收过于频繁,性能有较大损耗 - 可以使用结构体,减少对象创建、垃圾回收的开销
结构体适合用于封装简单的数据,例如坐标点(Point)、复数(Complex Number)、时间段(TimeSpan)等
参考文章:
结构类型 - C# reference | Microsoft Learn
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)