.NET源码学习 [算法2-数组与字符串的查找与匹配]( 二 )


文章插图
(二) 有关类String

.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图
String类位于命名空间System中 , 是一个公共密封类 , 继承了许多接口,其中“著名的”有:IComparable用于字符串间的比较;IEnumerable用于迭代器的遍历 。其内部包含2个属性,3个字段 , 1个结构(体),3种运算符的重载方法,9个构造方法和一堆其他方法(真的太多了) 。
1. 两个属性首先是索引器,可以发现这是一个以int为索引,char为返回值的只读索引器 。对比其他数据类型的索引器 , 如之前文章提到的动态数组ArrayList
.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图

.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图
不难发现,String中的索引器只读不能写,因此经常头昏会写出这样的代码:
.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图
同时,String类中的索引器还是一个extern属性,说明其支持在外部根据不同的需求重新定义新的索引器 。
.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图

.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图
第二个数Length属性,其内部包含了一个get_Length()方法,用于返回字符串的长度(调用的时候,不用在后面加括号 , 且第一个字母大写) 。
可以看到 , 这里都出现了Intrinsic和MethodImpl及其相关内容,这两个内容会在文末进行补充说明 。
2. 三个字段
.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图
string.Empty用于初始化字符串为空 。这里对四种初始化方式:(省略前缀string)str = null;str = “”;str = string.Empty;str = new()进行分析 。
(1)对于str = null,理论上这种方式不能称之为常规意义上的初始化,因为赋值为null并没有在堆上分配 , 仅是在栈上分配了空间,依然不可直接使用,因为变量不引用内存中的任何对象 。这种方式,相当于只定义了一个变量并未对其赋值,在使用前必须先赋值 。
(2)对于str = “”与str = string.Empty , 其初始化并在内存空间堆与栈上都进行分配 , 将其赋值为空 。其在基本用法和性能上并没有较大差异 。
.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图
据测试后可知,即使已存在一个空字符串,用以上两种方法继续进行定义变量 , 均不会重新申请新的内存空间 , 而是每次去指向固定的静态只读内存区域 。
据CLR中的相关信息及本人的理解,二者仅仅在优化方面稍有差别 , string.Empty是C#对""在语法级别的优化 。也就是说 , ""是通过CLR(Common Language Runtime公共语言运行库)进行优化的,CLR会维护一个字符串池,以防在堆中创建重复的字符串 。而string.Empty是一种C#语法级别的优化,是在C#编译器将代码编译为IL(即MSIL)时进行了优化,即所有对string类的静态字段Empty的访问都会被指向同一引用,以节省内存空间 。
还有两外两个字段 。这两字段从命名来看,一个变量存储的是字符串的长度;另一个存储的是第一个字符 。有关二者的应用及更多内容,会在之后的某些方法中进一步解释 。
.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图

.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图
3. 一个结构(体)
.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图

.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图
该结构体派生自类object下的类ValueType,从父类来看应该是用于存储某些数据类型间的映射关系 。(下方翻译来自Microsoft Bing)
.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图
4. 三种运算符重载
.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图

.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图

.NET源码学习 [算法2-数组与字符串的查找与匹配]

文章插图
首先是运算符“==”和“!=” 。对于两个字符串的比较,类String内部从新定义了比较规则,即重载了判断运算符,使用判断运算符就相当于调用类String内部的Equals()方法 。因此,对于字符串而言,使用“==”和方法Equals()进行比较,是完全等价的 。

推荐阅读