您的位置:首页 > 编程语言 > C#

CLR via C# 学习笔记(2012/3/11)

2012-03-11 21:20 218 查看
第14章 字符、字符串和文本处理

字符Char

一个16位Unicode码,包括很多静态方法,例如:IsDigit,IsLetter等,这里就不细说了。

字符串String

这才是需要讨论的重点。string是一个使用率很高的类型,尤其在Web应用中。

String类型直接派生自Object,所以它是一个引用类型,因此,String存在于堆上,而不是线程栈。C#将String视为一个基元类型,也就是说可以直接用文本量表示,而不用使用new运算符来分配。要注意的一点,编译器会将文本常量放在元数据中。多个文本常量通过+连接,将视为一个String而保存到元数据中。

String还有一个特点:不可变。一经创建,String的内容就不能更改,任何更改操作只是创建一个新的String而已。也由于不可变的特点,可以使用字符串留用技术来节省内存。

如果应用程序经常对字符串运行区分大小写、序列式的比较,或者事先知道许多字符串对象都有相同的值,就可利用CLR的字符串留用机制来显著提高性能。下面是一个例子:

public static void Main(string[] args)
{
string s1 = "Hello";
string s2 = "Hello";
Console.WriteLine(Object.ReferenceEquals(s1, s2));

string s3 = string.Format("{0}", "Hello");
string s4 = "Hello";
Console.WriteLine(Object.ReferenceEquals(s3, s4));

string s5 = string.Intern(s3);
string s6 = string.Intern(s4);
Console.WriteLine(Object.ReferenceEquals(s5, s6));
}
执行结果为:True False True

第一组比较为True的原因是因为编译器对文本常量是保存在元数据中的,并且只有一份,其他对这个文本常量的引用都是引用元数据中的这个引用。

第二组的值是一样的,但是这是两个不同的字符串,所以引用也就不一样了。

第三组使用了字符串留用的技术,将字符串保存在一个哈希表中,Intern(string s)检查是否有相匹配的,如果存在就返回一个引用,不存在则添加并返回引用。

在前一段时间,现在所在的公司的技术总监当时问了我们一个问题:两个String对象内容一样的,在最后生成时,是一个对象还是两个对象。当时我的回答是两个对象,而总监说只有一个,CLR会帮我们处理好。直至我看到本章后,我就知道总监这个回答不全对,他只说了文本常量只会有一份,正如第一组一样,而第二组就明显也是一样的内容,但是它们是两个对象。

字符串池

字符串池也就是刚刚说的,每个文本常量都会嵌入到元数据中,引用该字符串的代码都会被修改,改为指向在元数据中的地址,这就能够有效地提高性能并减少模块大小。

StringBuilder

StringBuilder是为了解决String的不可变而引入的一个可变字符串。对于在需要经常改变字符串的场合,使用StringBuilder能够有效提高性能,这是因为StringBuilder能够动态增减,当需要的时候调用ToString()方法能够返回所需要的String,能够避免不停地创建String,而导致提前垃圾回收。

使用StringBuilder的时候要注意,如果能够预先知道大概需要多大空间,可以在创建的时候指定空间,因为StringBuilder默认只有16个字符长度,当超出长度时,StringBuilder会自动扩大一倍,但这样会伴随一次的内存分配和数据复制的过程,假如所需空间很大,就会多次重复,这也会影响性能。

本章后面的内容本人没怎么接触过,看了也没什么感受,因此也就不写了。

第15章 枚举

枚举可以想像成是常量的强化版。以前使用一些公用的数值的时候,经常使用常量来定义,但是当我们需要遍历时,常量就处理不了了。现在我们有枚举这一利器,大大方便了我们编程。

枚举直接派生于System.Enum=>System.ValueType=>System.Object,所以枚举是值类型。

internal enum Color
{
White,
Red,
Green,
Blue,
Orange
}
重要提示:枚举类型定义的符号是常量值,所以当编译器遇到一个枚举符号时,就会编译时用数值替换符号,也就是说,在运行时可能并不需要加载枚举所在的程序集。

由于c#编译器将枚举类型视为基元类型,所以可以使用一些操作符(==,!=,+,-,&,|)等来操作枚举类型的实例。

枚举还有一用处:能够遍历枚举中定义的值:

Color[] colors = (Color[])Enum.GetValues(typeof(Color));
Console.WriteLine("Number of symbols defined: " + colors.Length);
Console.WriteLine("Value\tSymbol\n------\t-------");
foreach (Color c in colors)
{
Console.WriteLine("{0,5:D}\t{0:G}", c);
}


最后,枚举可以用作标志位:
[Flags]
internal enum Actions
{
None                = 0,
Read                = 0x0001,
Write               = 0x0002,
ReadWrite           = Actions.Read | Actions.Write,
Delete              = 0x0004,
Query               = 0x0008,
Sync                = 0x0010
}


Actions actions = Actions.Read | Actions.Delete;    //0x005
Console.WriteLine(actions.ToString());              //"Read, Delete"


标志位与一般的枚举区别在于,标志位添加了FlagsAttribute特性。

向枚举添加方法用到了扩展方法功能,感觉上就像是使用枚举方法一样。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: