网站首页 全球最实用的IT互联网站!

人工智能P2P分享Wind搜索发布信息网站地图标签大全

当前位置:诺佳网 > 软件工程 > 后端开发 > .Net >

.NET 结构体

时间:2024-12-27 19:27

人气:

作者:admin

标签:

导读:我们都知道结构体struct,在大量创建、引用的场景下相比类class能提升很大性能。本文介绍下如何正确使用struct struct定义 1 struct Point 2 { 3 public float X; 4 public float Y; 5 } 6 7 class Rect 8 { 9...

我们都知道结构体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

Struct 和 Class 的区别以及使用场景_struct和class使用场景-CSDN博客

作者:唐宋元明清2188 出处:http://www.cnblogs.com/kybs0/ 让学习成为习惯,假设明天就有重大机遇等着你,你准备好了么 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
温馨提示:以上内容整理于网络,仅供参考,如果对您有帮助,留下您的阅读感言吧!
相关阅读
本类排行
相关标签
本类推荐

CPU | 内存 | 硬盘 | 显卡 | 显示器 | 主板 | 电源 | 键鼠 | 网站地图

Copyright © 2025-2035 诺佳网 版权所有 备案号:赣ICP备2025066733号
本站资料均来源互联网收集整理,作品版权归作者所有,如果侵犯了您的版权,请跟我们联系。

关注微信