字符串处理
1 System.String是值类型还是引用类型
2 StringBuilder类型有何作用
3 如何在String和Byte[]对象之间进行转换
4 简述BASE64编码的作用以及C#中对其的支持
5 SecureString的实例如何被分配和释放
6 什么是字符串池机制
字符串处理
1 System.String是值类型还是引用类型
System.String 是引用类型,它的对象在初始化后就不能再做修改,任何试图修改字符串对象的动作都将导致一个新的字符串对象的产生。
示例代码:
static void Main(string[] args) { String a = "我是字符串"; String b = a; Console.WriteLine(Object.ReferenceEquals(a, b)); //尝试使用引用b修改a指向的对象 b = "我是新的字符串"; Console.WriteLine(a); Console.WriteLine(b); Console.WriteLine(Object.ReferenceEquals(a, b)); Console.Read(); }
输出结果:
True
我是字符串
我是新的字符串
False
String的性能问题产生于其内容不可修改的特性。当一个字符串对象被修改、插入、连接、截断是,新的字符串对象将被分配,这会影响性能。更加常见的情况是,一个字符串对象的最终生成需要经过一个组装过程,而在这个组装过程中必将产生很多临时字符串对象。这些对象在堆上分配,需要垃圾回收器来回收,这些动作会对程序产生巨大的影响。而事实上,在字符串组装过程中,其临时对象都不是最终需要的,可以说是不必要分配的。
这样就产生了对StringBuilder类型的需求。StringBuilder类型的设计思想源于构造器的设计模式。构造器设计模式致力于解决复杂对象的构造问题,而对于字符串对象,正需要这样的构造器来进行组装。StringBuilder类型在最终产生String对象之前,将不产生任何String对象,这很好的解决了字符串的性能问题。一旦StringBuilder的ToSting方法被调用后,最终的字符串就被产生,而随后的操作将导致一个新的字符串对象的分配。
对于非托管的代码,字符串的操作是直接基于内存的,如果使用字符串类型和非托管资源进行操作,那潜在地违反了字符串对象不可变的原则。所有StringBuilder常常别用来和非托管代码进行交互。
比特
比特(bit)是指一个位。
字节
字节(byte)在C#中由8个比特来构成。它的值可以由一个0~255的整数表示,但是C#中不允许隐式地把一个整数变量赋值给一个字节变量,下面的代码将编译错误:
int i = 10;
byte b = i;
编码
编码可以说是数字信息和现实信息的转换机制。一种编码常常就定义一种字符集合转换的原则,常用的编码方式包括UTF8、GB2312、Unicode 等。
字符串和字节数组的转换依赖于编码方式的使用,不同的编码准则使用不同的算法进行。System.Text.Encoding类型提供了大部分常见的编码算法支持,用以进行字符串和字节数组直接的转换。
示例代码:
class StringByte { static void Main(string[] args) { String s = "我是字符串,I am string"; //字节数组转换到字符串 Byte[] utf8 = StringToByte(s, Encoding.UTF8); Byte[] gb2312 = StringToByte(s, Encoding.GetEncoding("GB2312")); Byte[] unicode = StringToByte(s, Encoding.Unicode); Console.WriteLine(utf8.Length); Console.WriteLine(gb2312.Length); Console.WriteLine(unicode.Length); //转换回字符串 Console.WriteLine(ByteToString(utf8, Encoding.UTF8)); Console.WriteLine(ByteToString(gb2312, Encoding.GetEncoding("GB2312"))); Console.WriteLine(ByteToString(unicode, Encoding.Unicode)); Console.Read(); } static Byte[] StringToByte(String s, Encoding encoding) { return encoding.GetBytes(s); } static String ByteToString(Byte[] b, Encoding encoding) { return encoding.GetString(b); } }
输出:
27
22
34
我是字符串,I am string
我是字符串,I am string
我是字符串,I am string
BASE64编码是一种用于混淆明码的编程方式,其算法是把原来8位字节数组顺序分配到新的6位字节数组中,再在每个字节的高2位填充0来组成新的8位字节数组。在.NET中Covert类型可以用来进行BASE64字符串和8位字节数组之间的转换。
static void Main(string[] args) { String abc = "abcde"; //生成UTF8字节数组 Byte[] bytes = Encoding.UTF8.GetBytes(abc); //转换成Base64字符串 String base64 = BytesToBase64(bytes); Console.WriteLine(base64); //转换回UTF8字节数组 bytes = Base64ToBytes(base64); //转换回字符串 Console.WriteLine(Encoding.UTF8.GetString(bytes)); Console.Read(); } //把8位字节数组转换成Base64字符串 static String BytesToBase64(Byte[] bytes) { try { return Convert.ToBase64String(bytes); } catch { return null; } } //把Base64字符串转换成8位字节数组 static Byte[] Base64ToBytes(String base64) { try { return Convert.FromBase64String(base64); } catch { return null; } }
输出:
YWJjZGU=
abcde
System.SecureString 提供了加密的字符串类型。其对象会被分配在非托管堆中,并以加密的形式保存。对于SecureString的操作都是逐字符的,SecureString会负责在操作时进行加密和解密。SecureString实现了标准的Dispose/Finalize方法,对象被释放是先被全部布置为0,以保证机密信息不会在内存中驻留过长时间。
static void Main(string[] args) { //使用using保证Dispose方法被调用 using (SecureString ss = new SecureString()) { //只能逐字符地访问SecureString对象 ss.AppendChar('a'); ss.AppendChar('c'); ss.AppendChar('d'); ss.InsertAt(1, 'c'); PrintSecurityString(ss); Console.Read(); } } public unsafe static void PrintSecurityString(SecureString ss) { char* buffer = null; try { //只能逐字符地访问SecureString对象 buffer = (char*)Marshal.SecureStringToCoTaskMemUnicode(ss); for (int i = 0; *(buffer + i) != '