C#8.0本质论第十章--合式类型

news/2025/3/16 6:20:53/

C#8.0本质论第十章–合式类型

10.1重写object的成员

10.1.1重写ToString()

在对象上调用ToString()默认返回类的完全限定名称。

10.1.2重写GetHashCode()

如果重写Equals(),就要重写GetHashCode(),否则编译器会显示警告。

10.1.3重写Equals()

对象同一性"和"相等的对象值

两个引用加入引用同一个实例,就说这两个引用是同一的。object提供名为ReferenceEquals()的静态方法来显示检查对象同一性。

只有引用类型才可能引用相等,因此提供了对同一性概念的支持。为值类型调用ReferenceEquals()总是返回false,因为值类型转换成object要装箱,两个值类型会单独装箱。

object.Equals()的实现只是简单调用了一下ReferenceEquals()

10.1.4用元组重写GetHashCode()和Equals()

10.2操作符重载

要注意不能实现赋值操作符,=的行为无法改变。

10.2.1比较操作符
10.2.2二元操作符
10.2.3二元操作符复合赋值

赋值操作符不能重载,但只要重载了二元操作符,就自动重载了其复合赋值形式(+=、-=、*=、>>=等)

10.2.4条件逻辑操作符

和赋值操作符相似,条件逻辑操作符不能显示重载,但由于逻辑操作符&和|可以重载,而条件操作符由逻辑操作符构成,所以实际能间接重载条件操作符。

10.2.5一元操作符
10.2.6转换操作符

从技术上讲,实现显示和隐式转换操作符并不是重载转型操作符(())。但由于效果一样,所以一般都将“实现显示或隐式转换”说成“定义转型操作符”。

public readonly struct Latitude
{// ...public Latitude(double decimalDegrees){DecimalDegrees = Normalize(decimalDegrees);}public double DecimalDegrees { get; }public static implicit operator double(Latitude latitude){return latitude.DecimalDegrees;}public static implicit operator Latitude(double degrees){return new Latitude(degrees);}// ...
}

operator要放在表示隐式或显示转换的implicit或explicit关键字后面。

10.2.7转换操作符规范

10.3引用其他程序集

C#底层和CLI框架允许将代码分散到多个程序集中。这样就可在多个可执行文件中重用程序集。

10.3.1引用库
10.3.2用dotnet CLI引用项目或库
10.3.3用Visual Studio2019引用项目或库
10.3.4NuGet打包
10.3.5用dotnet CLI引用NuGet包
10.3.6用Visual Studio1029引用NuGet包
10.3.7调用被引用的包或项目

10.4类型封装

类封装行为和数据,而程序集封装一组类型。

10.4.1类型声明中的public或internal访问修饰符

不添加任何访问修饰符的类或结构体会被默认声明为内部访问(internal),而嵌套类型则默认声明为私有访问。

成员的可访问性无法大于它所在的类型。例如将类声明成internal,它的public成员也只能从程序集中访问。

10.4.2protected internal类型成员修饰符
10.5定义命名空间

事实上,CLR对“命名空间”一无所知,类型名称都是完全限定的,其中包含了命名空间。

命名空间支持嵌套,以便对类进行层次化的组织。也可以使用完整命名空间名称,每个标识符都以句点分隔。

10.6XML注释

开发者可利用命令行选项,指示编译器将XML注释提取到单独的XML文件中。这样就可以根据XML注释生成API文档。

10.6.1将XML注释和编程构造关联
10.6.2生成XML文档文件

10.7垃圾回收

.NET中的垃圾回收器采用mark-and-compact算法。一次垃圾回收周期开始时,它识别对象的所有根引用,基于该列表,垃圾回收器可遍历每个根引用锁表示的树形结构,并递归确定所有根引用指向的对象。这样,垃圾回收器就可识别出所有的可达对象

它将所有可达对象紧挨着放一起,从而覆盖不可访问的对象所占的内存。

相较于长期存在的对象,最近创建的对象更有可能需要垃圾回收。为此,.NET垃圾回收器支持“代”(generation)的概念,它会以更快的频率尝试清除生存时间较短的对象。而那些在一次垃圾回收中“存货”下来的对象会以较低的频率清除。具体地说,共有三代对象,一个对象每次在一个垃圾回收周期中存活下来,它都会移动到下一代,直至最终移动到第二代。

迄今为止讨论的都是强引用,因其维持着对象的可访问性,阻止垃圾回收器清除对象所占用的引用。此外,框架还支持弱引用。弱引用不阻止对对象进行垃圾回收,但会维持一个引用。这样,对象在被垃圾回收器清除之前可以重用。

弱引用是为创建起来代价较高,而且维护开销特别大的引用对象而设计的。弱引用相当于对象的一个内存缓存。(个人不是很理解有什么用,为什么不直接维持一个强引用)

10.8资源清理

10.8.1终结器

**终结器(finalizer)**允许程序员写代码来清理类的资源。但不能显式调用,没有和new对应的操作符。垃圾回收器负责为对象实例调用终结器,因此开发者不能在编译时确定终结器的执行时间。唯一确定的是终结器会在对象最后一次使用之后,通常在应用程序正常关闭前的某个时间运行。程序被强行关闭时可能不会被调用。

终结器的声明与C++析构器的语法完全一致。

public class TemporaryFileStream
{public TemporaryFileStream(): this(Path.GetTempFileName()){ }// Finalizer~TemporaryFileStream(){try{Close();}catch (Exception ){// Write event to logs or UI// ...}}
}

终结器不允许传递任何参数,所以不可重载,不能显式调用,调用终结器的只能是垃圾回收器。因此为终结器添加访问修饰符没有意义。

由于垃圾回收器负责所有内存管理,所以终结器不负责回收内存。相反,它们负责释放像数据库连接和文件句柄这样的资源。

一定要在终结器中避免异常。

10.8.2使用using语句进行确定性终结

终结器的问题在于不确定性终结,基类库为这个使用模式提供了特殊接口。IDisposable接口用名为Dispose()的方法定义了该模式的细节。

最终生成的CIL代码与写一个显式的try/finally块完全一样。在finally块中调用dispose,总之,using语句只是提供了try/finally块的语法快捷方式。

从C#8.0开始,using语句有一个简化的写法:可以在声明单个变量的语句之前使用using关键字。这种写法只能声明一个变量,并且也要求其类型实现了IDisposable接口。该程序的运行越过了变量的作用区间后,该变量的Dispose()方法便会被自动调用。此外using关键字声明的变量还有一个限制,就是这种变量不能再被赋值为其他值。

10.8.3垃圾回收、终结和IDisposable

IDisposable.Dispose()方法包含对System.GC.SuppressFinalize()的调用,作用是从**终结队列(f-reachable)**中移除TemporaryFileStream类实例。这时因为所有清理都在Dispose()中完成了,而不是等着终结器执行。

有终结器的对象如果不显式dispose,其生存期会被延长,因为即使对它的所有显式引用都不存在了,f-reachable队列仍然包含对它的引用,使对象一直生存,直至f-reachable队列处理完毕。

10.9推迟初始化

使用推迟初始化,可在需要时才创建对象。

class DataCache
{// ...public TemporaryFileStream FileStream =>InternalFileStream??(InternalFileStream = new TemporaryFileStream());private TemporaryFileStream? InternalFileStream { get; set; } = null;// ...
}

如实例化代价微不足道或不可避免,就应该直接在声明时在构造函数中赋值。


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

相关文章

Lvs+Nginx+NDS

什么是?为什么?需要负载均衡 一个网站在创建初期,一般来说都是只有一台服务器对用户提供服务 ​ 从图里可以看出,用户经过互联网直接连接了后端服务器,如果这台服务器什么时候突然 GG 了,用户将无法访问这…

微机原理与接口技术-第八章常用接口技术

文章目录 定时控制接口8253/8254定时器定时器的应用 并行接口并行接口电路8255内部引脚工作方式工作方式0:基本输入输出方式工作方式1:选通输入输出方式 编程 并行接口的应用用8255方式0与打印机接口 数码管及其接口数码管的工作原理单个数码管的显示多个…

图纸管理制度 《五》

1、存档文件应由专人管理,其他人未征得管理人员同意,不得随意翻阅查看。 2、档案管理人员要认真贯彻执行公司相关制度,严禁泄露档案材料中的秘密。 彩虹图纸管理软件_图纸管理系统_图纸文档管理软件系统_彩虹EDM【官网】彩虹EDM图纸管理软件…

Redis之Lua脚本讲解

这里写自定义目录标题 1 Lua1.1 简介1.1.1 注释1.1.2 变量1.1.3 数据类型1.1.4 控制结构1.1.5 函数1.1.6 模块1.1.7 字符串操作1.1.8 错误处理1.1.9 标准库 1.2 Redis和Lua脚本结合优点1.3 Lua脚本应用和调试1.3.1 缓存更新1.3.2 原子操作1.3.3 数据处理1.3.4 分布式锁1.3.5 Re…

【Linux】解决缓存锁问题:无法获得锁 /var/lib/dpkg/lock-frontend

今天在运行apt-get update更新软件包后,突然发现安装新的软件出现了这个报错:正在等待缓存锁:无法获得锁 /var/lib/dpkg/lock-frontend。锁正由进程 1855(unattended-upgr)持有。如图。 这个错误通常是由于其他进程正在…

mysql经典问题(可用于面试提问)

mysql经典问题(可用于面试提问) 1.Where 后面的列顺序是不是要符合最左原则? Where a1 and b2 等价于 Where b2 and a1 最左原则指的是索引顺序,不是谓词顺序,以上两个条件都匹配(a,b) 复合索引。 2.Join 的顺序是…

2023阿里云双十一优惠活动「云上聚·创未来」价格和代金券领取

2023阿里云双十一优惠活动「金秋云创季」开始啦,10月27日到10月31日可以领满减优惠,到11月1日和11月11日之间可以购买云服务器等产品,11.12到11.30日赢最高百万上云抵扣金,阿里云百科aliyunbaike.com分享2023阿里云双十一优惠活动…

C++前缀和算法的应用:使数组相等的最小开销

本文涉及的基础知识点 C算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 题目 给你两个下标从 0 开始的数组 nums 和 cost ,分别包含 n 个 正 整数。 你可以执行下面操作 任意 次: 将 nums 中 任意 元素增加或者减小…