1. 字符 Char
字符是值类型,16位的Unicode编码.
Char.GetUnicodeCategory返回字符类型的枚举.
2. String
是一个引用类型,代表一个不可变的顺序字符集.分配在堆上.
C#编译器把String作为一个基元类型,可以直接定义文本常量,=,
Environment.NewLine返回由回车和换行符组成的一个字符串,如 : var s = "s" + Environment.NewLine + "";
尽量避免使用+操作符连接几个字符串.会分别创建字符串的.
String.clone和Tostring返回对同一个对象的引用,静态方法Copy返回一个含有相同字符的不用引用.
String 比较
string.Compare静态方法和StringComparison.要考虑CultureInfo的异同.
CultureInfo.CurrentUICulture和CultureInfo.CurrentCulture.
CultureInfo.CompareInfo.Compare
字符串留用
CLR创建一个哈希表,Key是字符串,Value是字符串的引用.垃圾回收器不能释放这些字符串,在AppDomain卸载时才会释放.
String.Intern 检索系统对指定 System.String 的引用,如果暂存了 str,则返回系统对其的引用;否则返回对值为 str 的字符串的新引用(创建副本,将副本加入哈希表)
string.IsInterned 如果 str 在公共语言运行时的暂存池中,则返回对它的引用;否则返回 nullSystem.Runtime.CompilerServices.CompilationRelaxationsAttribute控制由公共语言运行时的实时 (JIT) 编译器生成的代码的严格性.
System.Runtime.CompilerServices.CompilationRelaxations.NoStringInterning将程序集标记为不需要字符串暂留.这两个字段可设置程序集是否留用字符串.
CLR默认留用程序集中的源数据描述的文本常量.永远都不要以”字符串已留用”为前提进行编程,除非显示调用字符串留用.
var s1 = "hello";
var s2 = "hello";
var result = object.ReferenceEquals(s1, s2);
Console.WriteLine(result);输出为True(在2.0版本也是True…个人认为这个是因为字符串池的原因,不是字符串留用的原因,元数据信息中只有一个string)
var t1 = new string('s', 5);
var t2 = new string('s', 5);
result = object.ReferenceEquals(t1, t2);
Console.WriteLine(result);输出为False
字符串池
如果代码中有对一个字符串的多次引用,编译器会只在元数据中插入文本常量字符串,使用字符串的地方只是引用这个元数据中的字符串.这也能说明上边第一个代码输出为True的原因.
文本元素(抽象字符)
System.Globalization.StringInfo 提供功能将字符串拆分为文本元素并循环访问这些文本元素
3.StringBuilder
内部包含一个Char数组,有一个最大容量和倍增容量.
可以高效的操作字符串,不会导致多次的开辟新的字符串.
如果字符串的长度超过了Builder的设置长度,会导致重新分配内存有一个疑问,是重新分配Build的内存还是Char数组的内存,应该是重新分配的Char数组的内存.
4.ToString
调试器中鼠标移动到一个变量上方显示出来的提示,是调用对象的ToString方法获得的.
使用System.Globalization.CultureInfo.InvariantCulture来获得字符串的无具体语言文化的格式.
自定义FormatProvider实现指定格式的ToString,使用到的类有IFormatProvider,ICustomFormatter.IFormattable
NumberFormatInfo格式化数字,DateTimeFormatInfo格式化日期和时间,CultureInfo特定文化,ICustomFormatter自定义格式.
其中IFormattable(提供将对象的值格式化为字符串表示形式的功能),支持enumeration,numeric,date,time,timespan.String是不支持IFormattable的,没有实现这个接口.
5. 编码和解码
UTF-16也称为Unicode编码,每个16位字符编码成2个字节.
字节流的解码
假如通过NetWorkStream的方式读取字符串,可能以数据块的方式传递,第一次读取5个字节,第二次读取7个字节,这样会导致字节丢失.可以使用Decoder类解决,第一次解码剩下的一个字节会在解码下一个的时候加上.
6. 安全字符串
String对被垃圾回收之后,内存可能无法立即重用,导致字符串长时间留在内存中,引起不安全的因素.
System.Security.SecureString是安全字符串.在Dispose的时候,数据会被清0.字符串不再存在于内存中.
Marshal提供了对于他的一些操作方法.
7. 位标志和枚举方法
可以向枚举添加方法,使用扩展方法的方式添加.
8. 数组
所有数组都隐式实现Array类
Array.Copy是浅拷贝.
Array.CreateInstance可以创建下标大于0的数组,如: Array.CreateInstance(typeof(double), new int[] { 2, 2 }, new int[] { 2000, 3000 });,GetLowerBound获取数组下标.
stackalloc在栈上分配内存块.