.NET 结构体

打印 上一主题 下一主题

主题 851|帖子 851|积分 2553

我们都知道结构体struct,在大量创建、引用的场景下相比类class能提升很大性能。本文介绍下如何正确使用struct
struct定义
  1. 1 struct Point
  2. 2 {
  3. 3     public float X;
  4. 4     public float Y;
  5. 5 }
  6. 6
  7. 7 class Rect
  8. 8 {
  9. 9     public Point Position;
  10. 10 }
  11. 11
  12. 12 Rect rect = new Rect();
复制代码
上述代码中,rect的Position字段并没有分配到栈上,反而是和Rect的实例一起被分配到了托管堆中。除此之外,装箱也会导致结构体实例分配到托管堆:
  1. 1 Point point = new Point();
  2. 2 object obj = point; // 装箱,结构体转移到托管堆
复制代码
所以假如由于性能要求或者别的原因想限定struct只分配到栈上的话,可以添加ref:
  1. 1 ref struct Point
  2. 2 {
  3. 3     public float X;
  4. 4     public float Y;
  5. 5 }
复制代码
这种情况下,struct关键字前添加ref是指将结构体声明为只能在栈上分配的结构体,对于这种结构体,任何大概将其转移到托管堆的行为都将被制止(比方在引用类型中定义ref结构体字段,或者进行装箱操作):
  1. 1 class Rect
  2. 2 {
  3. 3     public Point Position; // 错误,Position会随着Rect实例转移到托管堆
  4. 4 }
  5. 5
  6. 6 Point point = new Point();
  7. 7 object obj = point; // 错误,point会被装箱到托管堆
复制代码
别的,ref声明的struct可以继续作为字段在新struct内声明:
  1. 1 ref struct PointNew
  2. 2 {
  3. 3     public Point Point; // 允许,因为XPoint同样保证了栈上分配
  4. 4 }
复制代码
还可以声明只读的ref结构体:
  1. 1 readonly ref struct PointNew
  2. 2 {
  3. 3     public Point Point; // 允许,因为XPoint同样保证了栈上分配
  4. 4 }
复制代码
使用struct

1. 结构体作为参数传递
  1. 1 Point p = new Point();
  2. 2 TestAdd(ref p);
  3. 3
  4. 4 void TestAdd(ref Point point)
  5. 5 {
  6. 6     point.X += 1;
  7. 7 }
复制代码
假如不是只传值而是需要变更数据,需要添加ref,否则TestAdd中point只会作为原来p的副本天生一个新结构体。那最终p中的X值还是初始值0。ref我们都熟悉了,值类型假如作为参数输入后,外部同步修改也是使用ref
2. 结构体存储大小
看下面这段代码,输出结构体在栈上所需的内存大小:
  1. 1     [StructLayout(LayoutKind.Auto)]
  2. 2     struct TestStorage
  3. 3     {
  4. 4         public byte A;
  5. 5         public int B;
  6. 6         public byte C;
  7. 7         public byte D;
  8. 8         public byte E;
  9. 9     }
  10. 10    // 输出
  11. 11     unsafe
  12. 12     {
  13. 13         Debug.WriteLine(sizeof(TestStorage));
  14. 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博客
出处:http://www.cnblogs.com/kybs0/让学习成为习惯,假设明天就有巨大机会等着你,你准备好了么本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保存追究法律责任的权利。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

小秦哥

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表