c#笔记-结构

news/2024/11/20 19:29:58/

装箱

结构是值类型。值类型不能继承其他类型,也不能被其他类型继承。
所以它的方法都是确定的,没有虚方法需要在运行时进行动态绑定。
值类型没有对象头,方法调用由编译器直接确定。

但是,如果使用引用类型变量(如接口或object)来存储一个值类型,
或者调用了从object类继承的方法(如ToString),那么会发生装箱
这时,这个值类型会在堆上创建一个副本,并为它添加对象头。此时它的行为和引用类型一样。

副本的意思是复制品

如果把一个引用类型的值强制转换为值类型,就会去掉它的对象头,
并把内容复制到目标位置,这称为拆箱

.Net不会记录这个装箱的数据,多次调用从object类继承的方法,
或多次赋值给不同的引用类型变量,都会重新进行装箱。

值类型直接存储自己的数据,而不是通过指针引用其他位置的数据。
值类型的位置取决于它是不是临时变量。如果它是一个方法的局部变量
或者是另一个栈上数据的字段,那它就是在上的。
如果它是作为引用类型的字段,或者是已经装箱的数据,那他就在上。

引用类型使用的堆内存,又称为托管堆
托管是指.Net能够管理堆内存的分配,监视,回收,释放等操作。
但这些操作都需要消耗一定的性能。
在栈上的数据都是临时的,它们的分配和使用不需要经过这么多操作。
所以未被装箱的值类型,比引用类型具有更高的性能。

结构

声明结构

结构使用struct关键字进行声明。它不能指定基类,也不能成为基类。但结构可以实现接口。
所有以struct声明的结构都继承自System.ValueType类型,这是所有值类型的基类,而System.ValueType继承自object类型。

引用类型的直接数据只是一个指针,所以以下声明是可行的。

internal class MyClass
{public MyClass my;//但是不能写 = new MyClass()
}

而结构是直接包含数据的,所以结构不允许声明自己类型的字段(也不能用多个结构间接套娃)。

internal struct MyStruct
{public MyStruct ms;//这是错误的
}

结构初始值

结构的初始值(使用default关键字,创建数组元素,或作为其他类型的字段)
是它所有字段都为default的情况。它不会经过任何构造器。

如果你声明一个结构变量,但没有对它的所有字段赋值,那么你不能使用这个变量,
因为它相当于一个未赋值的局部变量。

你可以直接对这个变量赋值一个新的结构实例,
或者如果这个结构的所有字段都是public的,那你可以逐个对它们赋值。

结构构造器

结构必须有一个无参的构造器,并且它必须是public的。
如果你没有定义无参的构造器,编译器会自动为你添加一个。
但是如果你自己定义了无参的构造器,那么它也必须是public的。

结构的字段初始值赋值会自动合并到你显式定义的构造器的开头。
如果你要使用初始值赋值,必须显式定义至少一个构造器。
编译器添加的无参构造器不会合并字段初始值。

相等判断

引用类型默认有一个==运算符的重载,它比较两个对象的引用是否相同。但结构没有这样的重载,如果你想使用==运算符,你必须自己重载它。
结构从object类继承的Equals方法在ValueType类中被重写了,默认实现是利用反射动态比较所有字段的相等性。反射是非常消耗性能的,所以强烈建议对每个自定义结构都重写Equals方法。

不可变性

结构只能对变量进行修改。一个从方法或属性获得的结构是无法对成员进行修改的。
结构类型的只读字段也无法对值进行修改。
因此如果要改变结构类型的属性的成员,必须先用变量接收整个结构。

struct Point
{public int X;public int Y;
}class Player
{public int Hp { get; set; }public Point Point { get; set; }
}
Player player = new Player();
//player.Point.X = 60;  不能这样赋值
Point point = player.Point;
point.X = 60;
player.Point = point;

只读结构

结构可以为它的方法,属性,索引器添加readonly修饰符。
这样的方法体中,不允许修改字段的值。

但是,如果调用了其他没有readonly修饰符的方法,属性,索引器,
那么会在方法开头创建一个防御性副本。也就是说,要对整个结构进行一次复制操作。

使用in参数可以创建一个引用传递参数。它可以以指针的方式访问原始数据。
但不允许对它做出修改。类似于readonly方法,在这里面无法修改它的字段,
但如果你调用了它没有readonly修饰符的方法,那也会创建一个防御性副本来保证原始数据不被修改。

所以,出于性能优化考虑,可以对整个结构使用readonly修饰符。
这样,它的所有字段都必须有readonly修饰符,而它的其他成员会视为具有readonly修饰符。

引用传递一个只读结构将保证不会创建防御性副本。

一个指针大小在32位程序中相当于一个int,在64位程序中相当于一个long。
避免复制是针对大型结构的优化。对于没有太大复制开销的小型结构,寻址过程可能导致得不偿失。

引用结构

引用结构在结构前添加ref修饰符,这意味着结构中可以包含引用变量字段。
引用变量是安全的托管指针,c#对它做了很多限制来保证安全。

引用变量只能存在于栈上,所以引用结构也只能存在于栈上。
为了避免引用结构出现在堆上:

  • 它只能作为局部变量或其他引用结构的字段
  • 它不能实现接口,因为转换为接口会导致装箱。
  • 它不能赋值给ValueTypeobject类型,也不能调用它们的方法(包括ToString
  • 不能声明引用结构的数组。
  • 它不能作为泛型的类型参数
  • 它不能被匿名方法或局部方法捕获
  • 它不能出现在迭代器或异步方法中

http://www.ppmy.cn/news/66758.html

相关文章

哪种蓝牙耳机戴着最舒服?佩戴最舒服的真无线蓝牙耳机

无论在地铁、咖啡厅、商场甚至是机场,佩戴蓝牙耳机可以让我们尽情地享受音乐,戴上耳机可以避免影响他人的同时也能避免隐私的泄露。因此这几年真无线蓝牙耳机也受到了广大网友的追捧。,下面分享几款佩戴舒适的蓝牙耳机给大家。 一、南卡小音…

2 ElasticaSearch安装

2 ElasticaSearch安装 2.1 安装 安装配置: 1、新版本要求至少jdk1.8以上。 2、支持tar、zip、rpm等多种安装方式。 在windows下开发建议使用ZIP安装方式。 3、支持docker方式安装 详细参见:https://www.elastic.co/guide/en/elasticsearch/refere…

ChatGPT聊天新玩意:如何让AI成为你的聊天好友?

目录 引言: 案例: 淄博旅游第一版本: 分析: 淄博旅游第二版本: 分析: 总结: 万能公式: 引言: ChatGPT是什么?今天用一句话概括,它就是新…

中学理化生实验室建设及配置要求

中学理化生实验室是中学阶段进行物理、化学、生物教学和研究的场所。其可以满足实验教学要求,实验室提供必要的仪器、设备、工具、材料等课程资源,方便学生熟悉并接触一些实验仪器设备,学习掌握基本实验技能。同时,实验室科学合理的方案配置&…

用Python在25行以下代码实现人脸识别

** OpenCV ** OpenCV是最流行的计算机视觉库。最初是用C/C编写的,现在它提供了Python的API。 OpenCV使用机器学习算法来搜索图片中的面孔。因为脸是如此复杂,没有一个简单的测试可以告诉你它是否找到了一张脸。相反,有成千上万的小模式和特…

别让你的云端“瘫痪”——教你如何优化云平台性能测试

目录 引言 目的 测试指标 系统性能指标 资源指标 中间件指标 数据库指标 稳定性指标 批量处理指标 可扩展性指标 可靠性指标 性能测试的过程 测试计划 性能测试项目检测与控制 测试分析 测试设计 测试执行 测试完成 性能分析 性能分析的前提 性能分析的流…

Protein Cell:基于R语言的微生物组数据挖掘最佳流程(大众评审截止14号晚6点)...

Protein & Cell综述:基于R语言的微生物组数据挖掘的最佳流程 近日,中国农业科学院刘永鑫组联合南京农业大学袁军组在国际期刊 Protein & Cell (IF 15.3) 发表了题为”“The best practice for microbiome analysis using R”的综述论文&#xf…

Java --- redis7之GEO实现地图地址推送

目录 一、大数据统计之GEO 1.1、面试题 1.2、获得地址的经纬度 1.3、GEO相关指令 1.4、需求分析 1.5、架构设计 1.6、代码实现 一、大数据统计之GEO 1.1、面试题 移动互联网时代LBS应用越来越多,交友软件中附近的妹子,外卖软件中附近的美食店铺…