[From 14] String,一些对String知识得查漏补缺
一.逐字字符串(verbatim string)
C#提供了一种特殊的字符串声明方式。采取这种方式,引号之间的所有字符都被视为字符串的和一部分。这种特殊声明称为”逐字字符串“,通常用于指定文件或目录的路径,或者与正则表达式配合使用。
例:string str = @"C:\Hello My World"
String对象最重要的一点就是不可变(immutable).
二.字符串比较的优化
1.执行序号(ordinal)相等性检查时,CLR快速测试两个字符串是否包含相同数量的字符。答案否定,字符串肯定不相等;答案肯定,字符串可能相等。然后,CLR必须比较每个单独的字符才能最终确认。而执行对语言文化敏感的比较时,CLR必须比较所有单独的字符,因为两个字符串即使长度不同也可能相等。
2.字符串留用:
因为字符串是“不可变”的,所以在内存中复制同一个字符串的多个实例纯属浪费。如果应用程序经常对字符串进行区分大小写的序号比较,或者事先知道许多字符串对象都由相同的值,就可利用CLR的字符串留用(string interning)机制来显著提升性能。CLR初始化时会创建一个内部哈希表。这个表中,键(key)是字符串,而值(value)是对托管堆中的string对象的引用。
String类提供了两个方法,便于你访问这个内部哈希表:
public static String Intern(String str);
public static String IsInterned(String str);
第一个方法,获得参数的哈希码,并在内部哈希表中检查是否有相匹配的。如果存在完全相同的字符串,就返回对现有String对象的引用。如果不存在完全相同的字符串就创建新的副本,将副本添加到内部哈希表中,返回对该副本的引用。
垃圾回收不能释放内部哈希表引用的字符串,因为哈希表正在容纳对他们的引用。除非卸载AppDomain或者进行程序终止,否则内部哈希表引用的String对象不能被释放。
和Intern方法一样,IsInterned方法也获取一个String,并在内部哈希表中查找它。但如果没有IsInterned会返回null,不会将字符串添加到哈希表中。
程序集加载时,CLR默认留用程序集的元数据中描述的所有字面值字符串。Microsoft知道可能因为额外的哈希表查找而显著影响性能。所以现在禁用此功能。C#编编译器在编译程序集时总是指定以下两个特性和标志。(CLR4.5版本选择忽视C#编译器插入的特性和标志)
所以除非显示调用String的Intern方法,否则永远都不要以“字符串已留用”为前提来写代
三.指定具体的格式和语言文化
为了使调用者能选择格式和语言文化,类型一你应该实现System.IFormattable接口:
public interface IFormattable
{
String ToString(String format,IFormatProvider formatProvider);
}
format告诉方法如果格式化对象。(例如:DateTime类型支持用"d"表示短日期,用“D”表示长日期,“g”表示常规(general),用“M”表示月/日)
formatProvider是实现了System.IFormatProvider接口的一个类型实例。IFormatProvider接口的基本思路是:当一个类型实现了该接口,就认为该类型的实例能提供对语言文化敏感的格式信息,与调用线程关联的语言文化应该被忽略。
例如:
1 Decimal price = 123.54M; 2 String s = price.ToString("C",new CultureInfo("vi-VN"));//System.Globalization.CultureInfo类型实现了IFormatProvider 3 MessageBox.Show(s);
四.将多个字符串格式化成一个字符串
这里就举两个例子作为说明好了
1 String s = String.Format("On {0},{1} is {2} years old.",new DateTime(2012,4,22,14,35,5),"Aidan",9); 2 Console.WriteLine(s); 3 //On 4/22/2012 2:35:05 PM,Aidan is 9 years old. 4 5 String s = String.Format("On {0:D},{1} is {2:E} years old.",new DateTime(2012,4,22,14,35,5),"Aidan",9); 6 Console.WriteLine(s); 7 //On Sunday,April 22,2012,Aidan is 9.000000E+000 years old.
Format方法解析格式字符串时,发现可替换参数0应该调用它的IFormattable接口的ToString方法,并为该方法的两个参数分别传递“D”和null。类似地,Format会调用可替换的参数2的IFormattable接口的ToString方法,并传递“E”和null。假如可替换参数0和2的类型没有实现IFormattable接口,Format会调用从Object继承(而且有可能重写)的无参ToString方法,并将默认格式附加到最终生成的字符串中。
五.安全字符串
String的不安全性:
1.如果允许执行不安全或非托管的代码,这些代码就可以扫描进程的地址空间,找到包含敏感数据的字符串,并以非授权方式加以利用。
2.即使String对象只用一小段时间就进行垃圾回收,CLR也可能无法立即重用String对象的内存,致使String的字符长时间保留再进程的内存中(尤其是假如String对象是较老的一代),造成机密数据泄露。
SecureString的介绍:
有的政府部门又严格的安全要求,对各种安全措施进行了非常具体的规定。为了满足这些要求,Microsoft在FCL中增添了一个更加安全的字符串类,即System.Security.SecureString.
构造SecureString对象时,会在内部分配一个非托管内存块,其中包含一个字符串数组。使用非托管内存是为了避开垃圾回收器的“魔爪”
1.这些字符串的字符是经过加密的,能防范任何恶意的非安全/非托管代码获取机密信息。
2.SecureString类实现了IDisposable接口,允许以简单的方式确定性地摧毁字符串中地安全内容。
SecureString的使用条件:
在最新的FCL限制了对SecureString类的支持,只有以下情况允许讲SecureString作为密码传递。