![.NET源码学习 [算法2-数组与字符串的查找与匹配]](http://shimg.jingyanzongjie.com/230724/1516295961-8.png)
文章插图
据测试后可知 , 即使已存在一个空字符串 , 用以上两种方法继续进行定义变量 , 均不会重新申请新的内存空间 , 而是每次去指向固定的静态只读内存区域 。
据CLR中的相关信息及本人的理解 , 二者仅仅在优化方面稍有差别 , string.Empty是C#对""在语法级别的优化 。也就是说 , ""是通过CLR(Common Language Runtime公共语言运行库)进行优化的 , CLR会维护一个字符串池 , 以防在堆中创建重复的字符串 。而string.Empty是一种C#语法级别的优化 , 是在C#编译器将代码编译为IL(即MSIL)时进行了优化 , 即所有对string类的静态字段Empty的访问都会被指向同一引用 , 以节省内存空间 。
还有两外两个字段 。这两字段从命名来看 , 一个变量存储的是字符串的长度;另一个存储的是第一个字符 。有关二者的应用及更多内容 , 会在之后的某些方法中进一步解释 。
![.NET源码学习 [算法2-数组与字符串的查找与匹配]](http://shimg.jingyanzongjie.com/230724/15162a3N-9.png)
文章插图
![.NET源码学习 [算法2-数组与字符串的查找与匹配]](http://shimg.jingyanzongjie.com/230724/15162910X-10.png)
文章插图
3. 一个结构(体)
![.NET源码学习 [算法2-数组与字符串的查找与匹配]](http://shimg.jingyanzongjie.com/230724/15162910I-11.png)
文章插图
![.NET源码学习 [算法2-数组与字符串的查找与匹配]](http://shimg.jingyanzongjie.com/230724/15162912Q-12.png)
文章插图
该结构体派生自类object下的类ValueType , 从父类来看应该是用于存储某些数据类型间的映射关系 。(下方翻译来自Microsoft Bing)
![.NET源码学习 [算法2-数组与字符串的查找与匹配]](http://shimg.jingyanzongjie.com/230724/15162942V-13.png)
文章插图
4. 三种运算符重载
![.NET源码学习 [算法2-数组与字符串的查找与匹配]](http://shimg.jingyanzongjie.com/230724/1516293330-14.png)
文章插图
![.NET源码学习 [算法2-数组与字符串的查找与匹配]](http://shimg.jingyanzongjie.com/230724/1516291T2-15.png)
文章插图
![.NET源码学习 [算法2-数组与字符串的查找与匹配]](http://shimg.jingyanzongjie.com/230724/1516295443-16.png)
文章插图
首先是运算符“==”和“!=” 。对于两个字符串的比较 , 类String内部从新定义了比较规则 , 即重载了判断运算符 , 使用判断运算符就相当于调用类String内部的Equals()方法 。因此 , 对于字符串而言 , 使用“==”和方法Equals()进行比较 , 是完全等价的 。
一般地 , 对于运算符“==”和Equals()方法 , 在比较方式上还是有所差异 。
(1)对于值类型和字符串 , 这两种方式均只比较内容;
(2)对于除字符串以外的引用类型 , 运算符”==”比较的是在栈中的引用(是否指向同一个对象);方法Equals()比较的是在堆中的内容(是否是同一个对象的引用) 。
但这样就有一个问题 , 我们知道C#对于字符串有某些优化 。一般地 , 内容相同的字符串不会开辟新的堆空间 , 而是指向储存在暂存池(堆的一部分 , Java中称为常量池)中的对象 。但以某些方式创建的字符串对象 , 并不会检查暂存池 , 而是直接在堆中开辟新空间 , 导致内容相同的字符串 , 栈和堆的地址均不同 。那么这样是否会导致判断运算符和方法Equals()出现问题呢?有关该部分的详细内容请转到文末的 [# 有关字符串的比较与暂存池]
![.NET源码学习 [算法2-数组与字符串的查找与匹配]](http://shimg.jingyanzongjie.com/230724/1516294434-17.png)
文章插图
其次是ReadOnlySpan<T> 。这是一种较为特殊的运算符重载 , 其中关键字implicit用于声明隐式的自定义类型转换运算符 。它可以实现2个不同类型的隐式转换 , 提高代码的可读性 。但是使用隐式转换操作符之后 , 在编译时会跳过异常检查 , 所以在使用隐式转换运算符前 , 应当在一定程度上确保其不会引发异常并且不会丢失信息 , 否则在运行时会出现一些意外的问题 。该隐式转换 , 是将string类型转换成ReadOnlySpan<char>类型 。
经验总结扩展阅读
- 【前端必会】不知道webpack插件? webpack插件源码分析BannerPlugin
- 如何开展学习十八大,提高了教育的质量
- 十岁小孩学习不太好跟家长又不会怎么教他呢
- 20220929-ArrayList扩容机制源码分析
- 高效上课学习方法
- 怎么做一个学习的人
- Optional源码解析与实践
- Go 源码解读|如何用好 errors 库的 errors.Is 与 errors.As() 方法
- .Net下的分布式唯一ID
- .NET 反向代理 YARP 代理 GRPC