串(三):.NET Framework String类的实现(上)
2012-04-20 15:06:26一、字符串类的概述
String类继承了IComparable、ICloneable、IConvertible、IEnumerable接口,以便调用者枚举、拷贝、转换容器中的字符。同时还继承了IComparable, IEnumerable, IEquatable,这表示源代码的编写者考虑到了对泛型的支持。如果使用C# 2.0以上标准的编译器编译代码,那么String类还需要继承这三个泛型接口。
String类是.NET Framework中最为重要的类型之一。
不可变对象,提供了多种字符串操作函数。
为StringBuilder类提供基础方法。
为了保证执行效率,String类的性能关键部分采用非托管C++代码编写:
- 数据寻址:例如:get_Chars等;
- 内存分配:例如:FastAllocateString等;
- 内存复制,移动。
二、System.String源代码的组成
String.cs实现主要源代码,其他多个源代码文件实现辅助和基础操作功能。
托管代码部分:
– unsafecharbuffer.cs / buffer.cs提供辅助数据操作;
– CultureInfo.cs/CompareInfo.cs为字符串比较,大小写处理提供和文化区域相关的代码实现;
– Normalization提供规格化处理。
非托管代码部分:
– Ecall.cpp / ecall.h实现托管代码到非托管代码映射,FCFuncStart(gStringFuncs)部分;
– Object.h实现String类的非托管结构映射和基本取值操作的功能;
– Comstring.cpp实现复杂字符串操作;
– Comnlsinfo.cpp/.h提供与文化区域相关的复杂字符串操作。
三、类的声明
在String类一开始定义了3个非常重要的私有变量m_arrayLength、m_stringLength和m_firstChar,这3个私有变量在非托管代码中也会拥有同样的声明。以保证托管代码到非托管代码的映射。
public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable, IComparable<String>, IEnumerable<char>, IEquatable<String>
{
//具体含义参见object.h中的StringObject类定义
[NonSerialized]
private int m_arrayLength; //保存string对象所开缓冲区数组长度
[NonSerialized]
private int m_stringLength; //字符串实际长度
[NonSerialized]
private char m_firstChar; //字符串的第一个字符,其地址为字符串实际的首字符
//.................其它代码
}
由于String类实现比较复杂,又设计到一些C++的代码。我也不能完全说清楚它的所有实现。后面的内容中我将只会谈到部分方法的实现,同时我不会涉及C++的代码实现(因为我也不是很明白)。
四、构造函数
提供了8种构造的重载形式用来构建字符串对象
[CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
unsafe public extern String(char *value);
[CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
unsafe public extern String(char *value, int startIndex, int length);
[CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
unsafe public extern String(sbyte *value);
[CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
unsafe public extern String(sbyte *value, int startIndex, int length);
[CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
unsafe public extern String(sbyte *value, int startIndex, int length, Encoding enc);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern String(char c, int count);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern String(char [] value, int startIndex, int length);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern String(char [] value);
在8种构造函数中,最基本的构造函数的声明:
unsafe public extern String(sbyte *value, int startIndex, int length, Encoding enc);
从该构造函数中可以得知,要给定一个指向字符串首地址的指针(sbyte *value),要创建的字符串在给定的字符串中的起始索引位置(int startIndex),字符串长度(int length),以及编码对象(Encoding enc)。
这些构造函数的都是通过外部非托管代码来实现的,具体的C++代码请参见object.h中的StringObject类定义。其实不论那种构造,最终都是调用CreateString静态函数创建的字符串对象。
unsafe static private String CreateString(sbyte *value, int startIndex, int length, Encoding enc) {
if (enc == null)
return new String(value, startIndex, length); // default to ANSI
if (length < 0)
throw new ArgumentOutOfRangeException("length",Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (startIndex < 0) {
throw new ArgumentOutOfRangeException("startIndex",Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
}
if ((value + startIndex) < value) {
throw new ArgumentOutOfRangeException("startIndex",Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
}
byte [] b = new byte[length];
try {
Buffer.memcpy((byte*)value, startIndex, b, 0, length);
}
catch(NullReferenceException) {
throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
}
return enc.GetString(b);
}
五、内部辅助函数
1.内存申请函数:FastAllocateString
该函数可以在托管堆上申请一片指定长度的内存,并返回一个String类型的引用地址。在String类中,凡是需要申请内存的地方,都是使用这个函数。该函数也通过非托管代码实现,其声明如下:
//内存申请函数
//该函数可以在托管堆上申请一片指定长度的内存,并返回一个String类型的引用地址。在String类中,凡是需要申请内存的地方,都是使用这个函数。
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static String FastAllocateString(int length);
2.填充字符串函数:wstrcpy
为了保证效率该函数进行了一些优化。首先在编辑器完成地址对齐操作,之后又每次以8字节(64位)为一次循环批次,进行数据复制。
//将smem中的charCount个字节复制到dmem中
//为了保证效率在进行实际的数据复制之前会在编译器完成对dmem与smem进行地址对齐操作
private static unsafe void wstrcpy(char *dmem, char *smem, int charCount)
{
if (charCount > 0)
{
//如果地址没有以2字节对齐,将指针地址加1,使得地址以2字节对齐
if (((int)dmem & 2) != 0)
{
dmem[0] = smem[0];
dmem += 1;
smem += 1;
charCount -= 1;
}
//每次以8字节(64位)为此次,进行数据复制
while (charCount >= 8)
{
((uint*)dmem)[0] = ((uint*)smem)[0];
((uint*)dmem)[1] = ((uint*)smem)[1];
((uint*)dmem)[2] = ((uint*)smem)[2];
((uint*)dmem)[3] = ((uint*)smem)[3];
dmem += 8;
smem += 8;
charCount -= 8;
}
if ((charCount & 4) != 0)
{
((uint*)dmem)[0] = ((uint*)smem)[0];
((uint*)dmem)[1] = ((uint*)smem)[1];
dmem += 4;
smem += 4;
}
if ((charCount & 2) != 0)
{
((uint*)dmem)[0] = ((uint*)smem)[0];
dmem += 2;
smem += 2;
}
if ((charCount & 1) != 0)
{
dmem[0] = smem[0];
}
}
}
3.字符串索引器:this[]
该操作实现代码为非托管函数COMString::GetCharAt。
//该操作实现代码为非托管函数COMString::GetCharAt
[System.Runtime.CompilerServices.IndexerName("Chars")]
public extern char this[int index] {
[MethodImpl(MethodImplOptions.InternalCall)]
get;
}
六、其它部分函数的实现
- 重载运算符
public static bool operator == (String a, String b) { return String.Equals(a, b); } public static bool operator != (String a, String b) { return !String.Equals(a, b); }
- 字符串特征函数
public static readonly String Empty = ""; //也是通过非托管代码来实现的 public extern int Length { [MethodImplAttribute(MethodImplOptions.InternalCall)] get; } public static bool IsNullOrEmpty(String value) { return (value == null || value.Length == 0); } public bool Contains( string value ) { return (IndexOf(value, StringComparison.Ordinal) >=0); }
- 字符串操作函数
[MethodImplAttribute(MethodImplOptions.InternalCall)] public extern String Insert(int startIndex, String value); [MethodImplAttribute(MethodImplOptions.InternalCall)] public extern String Replace (char oldChar, char newChar); [MethodImplAttribute(MethodImplOptions.InternalCall)] public extern String Replace (String oldValue, String newValue); [MethodImplAttribute(MethodImplOptions.InternalCall)] public extern String Remove(int startIndex, int count); public string Remove( int startIndex ) { if (startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex")); } if( startIndex >= Length) { throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndexLessThanLength")); } return Substring(0, startIndex); } public Object Clone() { return this; }
- 其它函数
public String ToLower() { return this.ToLower(CultureInfo.CurrentCulture); } public String ToLower(CultureInfo culture) { if (culture==null) { throw new ArgumentNullException("culture"); } return culture.TextInfo.ToLower(this); } public String ToLowerInvariant() { return this.ToLower(CultureInfo.InvariantCulture); } public String ToUpper() { return this.ToUpper(CultureInfo.CurrentCulture); } public String ToUpper(CultureInfo culture) { if (culture==null) { throw new ArgumentNullException("culture"); } return culture.TextInfo.ToUpper(this); } public String ToUpperInvariant() { return this.ToUpper(CultureInfo.InvariantCulture); } public override String ToString() { return this; } public String ToString(IFormatProvider provider) { return this; }