第Ⅳ部分 基本类型
第十二章 文本处理
12.1字符
一个字符由一个System.Char结构(值类型)实例表示。它提供两个常数字段:MinValue和MaxValue。
可以调用Char的静态方法GetUnicodeCategory返回一个System.Globalization.UnicodeCategory枚举值来判断字符的类型。
GetNumericValue返回一个字符的对应的数值形式。
12.2System.String类型
不能使用new操作符来创建String对象。不建议使用\n等转义符,应该使用System.Environment提供的方法。尽量少的使用+操作符来拼接字符串,因为它会在要执行垃圾收集的托管堆上创建多个字符串对象。
String对象的最重要特性便是恒定性,也就是一个字符串一旦被创建,我们就不可能再将其变长、变短、或者改变其中任何的字符。
P.256-257表12.1有关字符串比较的方法。
使用CompareInfo类的方法,进行排序比较等,相对于String类中的方法拥有更多的控制。
字符串比较损伤系统性能。
String s = “Hello”;
Console.WriteLine(Object.ReferenceEquals(“Hello”,s));
将返回True;
String s1 = “Hello”;
String s2 = “Hel”;
Srring s3 = s2+“llo”;
ReferenceEquals将返回False
Equals将返回True
S和”Hello”运行时,CLR会在第一次碰到的时候在散列表中创建”Hello”,当第二次碰到时,会将引用直接指向刚刚创建的散列表。S3动态创建的将是一个新的对象。
将相同字符集的动态字符变为托管堆中的一个字符串对象的话,应用程序需要的对象会大大减少,有利于系统性能的提升。可以使用Intern方法(查找后如没有则创建并返回引用)、IsInterned方法(查找后不创建返回null)
CLR帮我们在元数据中只写入一次相同的文本常量字符串,这样可以免去多个相同字符串带来的元数据文件膨胀。
P.266-267表12.2查看字符串中字符的一些方法。
使用代理项可以使Unicode可以表示较多字符,包括中文等。System.Globalization.StringInfo类型的静态方法GetTextElementEnumerator来枚举字符创中包括的所有抽象Unicode字符。
包括拷贝、Inser、Remove等等其他方法,返回的都是新字符串,因为是字符串恒定不变的。
12.3高效地动态创建字符串
System.Text.StringBulider对象,在内部指向一个Char结构数组的字段。在构建完成后可以使用ToString()方法转换为一个String对象。
StringBulider sb = new StringBulider(“…”);
内部维护的字段:①最大容量,可以容纳字符的最大长度,默认20亿;②容量,维护的字符数组字段的长度。③字符数组。
为了获得更高的性能,不会分配新对象,不会保证线程安全。
P.273-274表12.4StringBulider的成员
12.4获取对象的字符串表达形式
重写ToString方法。
ToString()方法中的IFormatProvider接口规范,默认返回当前线程的System.Globalization.CultureInfo类型实例。
使用静态的Format方法,StringBulider使用AppendFormat方法,工作原理类似。
12.5通过解析字符串获取对象
大部分类型都提供了解析字符串的静态方法Parse。参数NumberStyles(数字类型)是一个位标记枚举类型,标识可能在字符串中出现的字符形式。
P286-287表12.5NumberStyles类型定义的位符号
P287表12.6NumberStyles类型定义的位组合符号
P289表12.DateTimeStyles类型定义的位符号
12.6编码:字符与字节之间的转换
System.Text.Encoding的静态属性,Default取决于用户计算机,GetEncoding(“”)可以填入需要的编码对象来构建。
P293表12.8继承自Encoding类的属性
P296表12.9继承自Encoding类的方法
使用System.Convert类型提供的一些静态方法来实现FromBase64String、FromBase64CharArry
第十三章 枚举类型与位标记
13.1枚举类型
好处:①使得程序更容易编写、阅读和维护;②枚举类型是强类型。
枚举类型就是一个定义了一组常数字段的结构而已,编译后存放在生成模块的元数据中,并通过反射来访问。
静态方法GetUnderlyingType(Type enmuType)返回用于保存枚举类型实例值的基础类型(underlying type),使用基元类型定义基础类型 enmu Color:byte。ToString()方法会默认调用Fromat方法,允许我们传递枚举值的数值形式。GetValues允许我们获取一个枚举中定义的所有符号。GetName方法返回枚举符号。Parse方法将文本符号转换为一个枚举实例。IsDefined判定数值对于某个枚举类型是否合法。枚举类型应该定义在需要它的类型的同一层次上,而不是该类型中。
13.2位标记
在需要作为位标记的枚举上定义特性[Flags]或[FlagsAttribute],可以将枚举数值看做是一组标记,而非一个单独的数值。
第十四章 数组
数组总是分配在托管堆上的引用类型,并且应用程序中的数组变量包含的是一个指向数组的引用,而非数组本身。
CLS要求所有的数组都是0基数。
我们应该尽可能的使用一维0基数组,有称作SZ数组(single-dimension、zero-based数组),或者向量(vector),性能最好。
多维数组:String[,,,,,…] = new String[2,5,6,8,10,20…];
交错数组:数组中包含数组。
14.1所有数组的基类:System.Array
P.312-313-314表14.1System.Array的成员
14.2数组的转型
Array.Copy方法:①装、拆箱;②拓宽CLR基元类型;
14.3数组的传递与返回
14.4创建下限非0的数组
CreateInstance方法动态创建。
14.5快速数组访问
Fixed(Int32* element=&arr[0]){……}
只能用于部分类型,不包括String
14.6重新调整数组长度
使用CreateInstance方法
第十五章 接口
15.1接口与继承
接口与基类设计指导:
① IS-A(基类)与CAN-DO(接口)关系
② 易用性,基类比较灵活,接口必须实现其全部成员
③ 一致的实现
④ 版本
15.2设计支持插件组件的应用程序
① 创建一个程序集,然后在其中定义接口,接口的方法将用于应用程序和插件组件的通信机制
② 创建一个单独的程序集用于包含我们的应用程序所使用的其他类型
③ 插件开发人员会在他们的程序集中定义自己的类型
15.3使用接口改变已装箱值类型中的字段
15.4实现多个有相同方法的接口
接口1.a();接口2.a();
15.5显式接口成员实现
提供类型开全,减少值类型的装箱操作。应尽量谨慎的使用,会带来代码的混乱及编写的麻烦。
第十六章 定制特性
16.1使用定制特性
它们仅仅是为目标元素提供关联附加信息的一种方式。C#允许我们将特性引用于:程序集、模块、类型、字段、方法、方法参数、方法返回值、属性、事件。指定前缀可消除二义性,如[assembly:MyAttribute(1)](应用于程序集)、[type:MyAttrbute(3)](应用于类型)等,P.347-348。一个特性就是类型的一个实例,该类型必须有一个工友构造器来创建它的实例。
16.2定义自己的特性
特性是一个继承自System.Attribute的类型。
[AttributeUsage(AttributeTargets.……,Inherited = true/false)]
AttributeTargets指定自己定义的特性可以应用在什么类型上面。
Inherited表示特性是否应该应用于派生类或者派生方法上。
AllowMultiple表示特性在同一个类型上是否可以多次调用。
如果没有使用AttributeUsage,默认为:它可以应用于所有的目标元素;它在一个目标元素上只可以应用一次;它可以被继承。
16.3特性构造器与字段/属性的数据类型
16.4检测定制特性
P.356表16.1System.Attribute类的一些方法
① IsDefined如果有至少一个Attribute的派生类应用在目标元素上,返回true
② GetCustomAttributes应用在目标元素上的特性实例数组,通常用于AllowMultiple=true
③ GetCustomAttribute返回一个指定的、应用在目标元素上的特性,用于AllowMultiple=false
System.Reflection命名空间中定义的一些类型允许我们查看一个模块中的原数据内容。这些类型也都提供了IsDefined和GetCustomAttributes方法。只有Attribute提供了GetCustomAttribute。
16.5特性实例间的匹配
充写Match方法,对实例进行类型比较(this与传递进来的)。
16.6伪定制特性(pseudo-custom attribute)
GetCustomAttributes等方法无法检测Serializable等这些常用特性,微软对其进行压缩优化,可以通过System.Type的一些只读属性来进行监测。
第十七章 委托 -- 大量编码例程
17.1认识委托(delegate)
17.2使用委托回调静态方法
17.3使用委托回调实例方法
17.4委托揭秘
编译器会将一个委托完整的编译为一个类,包括:一个构造器、Invoke、BeginInvoke、EndInvoke四个方法。
所有委托继承自MulticastDelegate类,P.372表17.1MulticastDelegate中几个重要的私有字段
17.5委托史话System.Delegate与System.MulticastDelegate
System.MulticastDelegate(表示可以被链接在一起的委托对象)
System. Delegate。(表示单个委托对象)
目前,因为这两个类带来的困惑,微软修改了编译器,基本全部继承自System.MulticastDelegate。
17.6委托判等
Delegate重写了Object的Equals虚方法,MulticastDelegate又重写了Delegate的Equals实现。MulticastDelegate重写的Equals方法在比较两个委托对象时会首先看它们的_target和_methodPtr字段是否都指向同样的对象和方法。如果这两个字段不匹配,返回false,如果匹配,那么再看两个委托对象是否表示委托链表的头部——也就是说它们的_prev字段不为null,两个委托对象的_prev字段指示的链表有相同的长度,那么返回true,否则返回false。
17.7委托链
每个MulticastDelegate委托的_prev用于指向另一个MulticastDelegate对象的引用。因此,可以组合成一个链表。
使用System.Delegate的Combine进行操作。
Delegate.Combine(DG1,DG2);组合两个并返回DG2,它是链表的末端(先被调用)
Delegate.Combine(DG[]);创建由数组表示的链表,0为链表尾部,并且是末端(先被调用)
Delegate.Remove(DG,value);从链表中移除一个和value的回调目标/方法向匹配的委托,新的链表头将会被返回,并且是末端(先被调用);如果没有找到,则不执行任何操作,返回传递给它的第一个参数。
C#重载了+=和-=操作符调用Combine和Remove方法。
17.9对委托链调用施以更多的控制
GetInvocationList()方法,创建一个委托数组,每个元素都是委托链上对象的一个克隆,0是尾部,第一个调用。
17.10委托与反射