语言文化:使用CultureInfo类型来表示一个"语言/国家"对。具有以下特性;
1.内部包含一个CompareInfo类型成员。该成员主要用来封装语言文化的字符排序表信息。
2.Thread.CurrentUICulture属性表示UI元素上用到的语言文化。默认值为GetUserDefaultUILanguage函数获取的值。
3.Thread.CurrentCulture属性表示非UI环境下用到的语言文化。默认值为GetUserDefaultLCID函数获取的值。
字符:使用Char类型来表示一个16位的Unicode代码值。具有以下特性:
1.常见的函数如下所示:除了特殊说明字符的编码,以下字符都是UTF-16字符。
1>.GetUnicodeCategory:获取指定字符的UnicodeCategory枚举类型。而该枚举类型中定义了控制字符,货币符号,小写字母,大写字母,标点符号,数学符号以及其他字符。
2>.ToLowerInvariant / ToUpperInvariant:以忽略语言文化的方式将指定字符转换成小写字符或者大写字符。
3>.ToLower / ToUpper:以线程关联的语言文化或者自己指定的语言文化的方式将指定字符转换成小写字符或者大写字符。
4>.Equals:用来比对两个字符的Unicode值是否相等。
5>.CompareTo:以忽略语言文化的方式来返回两个字符的比对结果。
6>.ConvertFromUtf32:用来将一个UFT-32字符生成一个或者两个字符的字符串。
7>.ConvertToUtf32:用来将一个或者两个字符的字符串生成一个UFT-32字符。
8>.ToString:用来生成包含单个字符的字符串。
9>.Parse / TryParse:用来获取包含单个字符的字符串中的该字符。
10>.GetNumericValue:用来获取字符的数值形式。
2.字符类型和数值类型相互转换的方式如下所示:
1>.强制类型转换(最高效):编译器会生成IL代码来完成转换,从而不用调用任何转换函数。
2>.使用Convert类型(次高效):以checked方式来执行转换,所以当出现数据溢出时就抛出异常。
3>.使用IConvertible接口(最低效):在调用转换函数时,如果存在类型不能转换或者数据溢出时就抛出异常;否则就存在值类型到接口类型的装箱操作。
字符串:使用String类型来表示不可变的顺序字符集。具有以下特性:
1.使用安全代码时,不能通过构造函数来创建String类型实例,但是可以通过ldstr(即load string)IL指令以加载字面值的方式来创建String类型实例。
2.使用不安全代码时,可以通过接受Char或者Sbyte的构造函数来创建String类型实例。
3.可以使用Environment类中的NewLine属性来获取跨平台的换行字符串。
4.使用@符号来声明的字符串叫做逐字字符串。它表示引号之间的所有字符(包括转义符)都会被视为字符串的一部分。
5.建议使用Compare函数来做字符串的相等性判定和排序。具有以下特性:
1>.建议排序时要区分大小写。
2>.C#针对大写字符串的比较进行过优化。
3>.忽略语言文化是最快的比较方式。而StringComparison中的Ordinal或者OrdinalIgnoreCase比StringComparison中的InvariantCulture或者InvariantCultureIgnoreCase的执行效率更高。
4>.不忽略语言文化时,Compare函数内部调用CultrueInfo类中CompareInfo属性的Compare函数来进行比较,并且用CompareOptions枚举类型作为参数来限制比较范围。
6.可以使用StringInfo类中的接口来对抽象字符(也叫做文本元素)进行处理。
字符串留用:CLR内部维护一张哈希表。这个哈希表以字符串作为key,以托管堆中的字符串对象引用作为value。具有以下特性:
1.虽然C#编译器一直使用CompilationRelaxationsAttribute属性中的NoStringInterning标志值来将程序集的元数据中定义的所有字符串不留用到哈希表;但是CLR(4.5版本)可能忽略编译器的设置,从而将程序集的元数据中定义的所有字符串都留用到哈希表中。
2.String的Intern函数会查找哈希表中是否存在指定字符串,如果存在就返回哈希表中该字符串的引用;否则就先创建字符串副本,然后将字符串副本添加到哈希表中,最后返回哈希表中该副本的引用。
3.String的IsInterned函数会查找哈希表中是否存在指定字符串,如果存在就返回哈希表中该字符串的引用;否则就返回null。
4.字符串留用机制会增大内存开销,使用不恰当的话就会得不偿失,所以建议慎用。
StringBuilder:里面维护着一个可以动态扩容的字符数组来高效构造字符串。具有以下特性:
1.最大容量:指定可以放入字符串中最大的字符数,默认值为Int32.MaxValue。最大容量必须大于等于1。
2.当前容量:指定了字符数组的长度,默认值为16。当前容量不足时会动态倍增当前容量来创建新的字符数组,以前旧的字符数组可以被垃圾回收。当前容量必须大于等于0,小于等于最大容量。
3.确保容量:类似于最小容量。当前容量小于确保容量时,当前容量会自动增大到确保容量。
4.字符数组:指定字符串的字符内容,默认值为String.Empty。可以使用Length属性来获取和设置字符数组中已经使用的字符数。
5.调用ToString函数时会在托管堆上分配内存空间,并填充字符数组内容。
6.通过有参属性来获取和设置指定索引位置处的字符。
7.只有在具有相同最大容量,相同当前容量和相同字符数组内容时,调用Equals才会返回true,否则返回false。
对象的字符串表示:具有以下原则:
1.类型应该提供四个ToString函数。分别如下:
1>.重写IFormattable接口中的ToString函数。该函数允许指定具体的格式和语言文化。当格式为null时就使用默认格式(也就是常规格式G,它代表最常用的格式);当语言文化为null时就使用默认语言文化(也就是线程关联的语言文化)。
2>.重写Object类中的ToString函数。该函数内部以常规形式和线程关联语言文化形式来调用重写IFormattable接口中的ToString函数。
3>.提供只有格式参数的ToString函数。该函数内部会以指定格式和线程关联语言文化形式来调用重写IFormattable接口中的ToString函数。
4>.提供只有语言文化参数的ToString函数。该函数内部会以常规格式和指定语言文化形式来调用重写IFormattable接口中的ToString函数。
2.使用String类中的Format函数或者StringBuilder类中的AppendFormat函数来对多个对象格式化成一个字符串。具有以下特性:
1>.函数的format参数是string类型。它的形式为"{对象参数索引:格式}",其中":格式"是可选部分。
2>.函数的provider参数是IFormatProvider接口类型。它提供GetFormat函数用来获取字符串处理器。
3>.函数执行流程如下所示:
1>>.当provider参数不为空且实现了ICustomFormatter接口时,就会调用该接口的Format函数来将对象格式化成一个字符串。
2>>.当不存在1>>步骤中的字符串时,就会查看对象是否实现了IFormattable接口,如果实现了该接口的话,就会调用该接口的ToString函数来将对象格式化成一个字符串。
3>>.当不存在2>>步骤中的字符串时,就会调用Object类中的ToString函数来将对象格式化成一个字符串。
字符串解析成对象:具有以下原则:
1.类型应该提供四个Parse / TryParse函数。分别如下:
1>.参数列表分别为字符串参数。
2>.参数列表分别为字符串参数以及字符串中允许的样式参数。
3>.参数列表分别为字符串参数以及字符串语言文化参数。
4>.参数列表分别是字符串参数,字符串中允许的样式参数以及字符串语言文化参数。
2.类型Parse函数解析失败时就抛出异常,解析成功就返回类型对象。
3.类型TryParse函数解析失败时就返回false,解析成功就返回true和对象。
字符和字节的相互转换:字符通过编码转换成字节,字节通过解码转换成字符。具有以下特性:
1.FCL支持的编码格式如下表所示:
编码格式 | 是否常用 | 说明 |
---|---|---|
Base64 | 是 | 一种基于64个可打印字符来表示二进制数据的方法,常用在HTTP环境下传递较长的标识信息。 |
UTF-16 | 是 | 将16位字符编码成2个字节。不对字符产生任何影响,也不会压缩字符,所以性能非常出色。它可以从"低位优先"和"高位优先"之间相互转换 |
UTF-8 | 是 | 将值在0x0080之下的字符编码成1个字节,适合表示美国使用的字符;将值在0x0080~0x07FF之间的字符编码成2个字节,适合表示欧洲和中东语言;将值在0x0800以及之上的字符编码成3个字节,适合表示东亚使用的字符;将代理项对编码成4个字节。当许多字符值在0x0800以及之上时,UTF-16的效率会高于UIF-8。 |
UTF-32 | 否 | 将16位字符编码成4个字节。适用于简单遍历所有字符并且不愿意花额外精力处理字节数可变的字符。 它的内存使用并不高效,同时可以从"低位优先"和"高位优先"之间相互转换。 |
UTF-7 | 否 | 用于使用7位表示字符的旧系统上,由于会造成数据膨胀,所以已经被Unicode协会淘汰了。 |
ASCII | 否 | 将16位字符编码成1个字节。当字符值大于等于0x0080的话就会出现字符丢失的情况。 |
2.Encoding类的派生类来完成字符串和字节数组之间的转换操作。具有以下特性:
1>.UTF-8 / UTF-7 / UTF-32 / ASCII等属性会返回对应编码对象并缓存到池中。
2>.Default属性会返回本机非Unicode字符使用的代码页设置的编码对象并缓存到池中。由于不同机器设置可能不同,为了保证程序行为(显示)的一致性,所以最好不要使用该属性。
3>.GetEncoding函数用来获取指定的编码对象并缓存到池中。
4>.GetBytes函数使用当前编码对象对字符串或者字符数组进行编码成字节数组。
5>.GetString函数使用当前的编码对象对字节数组进行解码成字符串。
6>.GetChars函数使用当前的编码对象对字节数组进行解码成字符数组。
7>.GetByteCount函数用来获取对字符数组进行编码时所产生的字节数组长度。
8>.GetMaxByteCount函数用来获取对指定字符数的字符数组进行编码时所产生的最大字节数组长度。
9>.GetCharCount函数用来获取对字节数组进行解码时所产生的字符数组长度。
10>.GetMaxCharCount函数用来获取对指定字节数的字节数组进行解码时所产生的最大字符数组长度。
11.GetPreamble函数用来获取前导码(也叫做字节顺序标记BOM)。对于UTF8Encoding而言,前导码为3字节数组(0xEF, 0xBB, 0xBF);对于UnicodeEncoding而言,前导码为2字节数组(0xFE, 0xFF)来表示高位优先编码,或者为2字节数组(0xFF, 0xFE)来表示低位优先编码。
12.Convert函数用来将字节数组从一种编码转换成另一种编码的字节数组。
13.Equals函数判定两个对象具有相同的代码页和前导码时就返回true,否则返回false。
14.GetEncoder函数会返回一个新的编码对象。该编码对象可以使用GetBytes和GetByteCount函数来保存字符状态并对字符数组以块的方式进行编码。
15.GetDecoder函数会返回一个新的解码对象。该解码对象可以使用GetChars和GetCharCount函数来保存字节状态并对字节数组以块的方式进行解码。
3.Convert类来完成字符串和字节数组之间的转换操作。具有以下特性:
1.FromBase64String / FromBase64CharArray函数用来将Base64字符串编码成字节数组。
2.ToBase64String / ToBase64CharArray函数用来将字节数组解码成Base64字符串。
安全字符串:类型为SecureString。具有以下特性:
1.分配一个非托管内存块,内部包含一个字符数组来负责维护加密的字符串。当字符串被回收时,该字符数组的内容会被清空,同时非托管内存块也会被释放。
2.可以使用Marshal类中提供的函数来将安全字符串解密到非托管内存缓冲区中。常见的函数如下表所示:
解密到缓存区函数 | 释放缓冲区函数 |
---|---|
SecureStringToBSTR | ZeroFreeBSTR |
SecureStringToCoTaskMemAnsi | ZeroFreeCoTaskMemAnsi |
SecureStringToCoTaskMemUnicode | ZeroFreeCoTaskMemUnicode |
SecureStringToGlobalAllocAnsi | ZeroFreeGlobalAllocAnsi |
SecureStringToGlobalAllocUnicode | ZeroFreeGlobalAllocUnicode |