第 18 章 定制特性本章内容
使用定制特性
定义自己的特性类
特性构造器和字段/属性数据类型
检测定制特性
两个特性实例的相互匹配
检测定制特性时不创建从 Attribute 派生的对象
条件特性类
利用定制特性,可宣告式地为自己的代码构造添加注解来实现特殊功能。定制特性允许为几乎每一个元数据表记录项定义和应用信息。
18.1 使用定制特性C# 只允许将特性应用于定义以下任何目标元素的源代码:程序集、模块、类型(类、结构、枚举、接口、委托)、字段、方法(含构造器)、方法参数、方法返回值、属性、事件和泛型类型参数。
定制特性其实是一个类型的实例。定制特性类必须直接或间接从公共抽象类 System.Attribute派生。
18.2 定义自己的特性类1234567namespace System { [AttributeUsage(AttributeTargets.Enum, Inherited = false)] public class FlagsAttribute : System.Attribute { public F ...
第 17 章 委托本章内容:
初始委托
用委托回调静态方法
用委托回调实例方法
委托揭秘
用委托回调许多方法(委托链)
委托定义不要太多(泛型委托)
C# 为委托提供的简化语法
委托和反射
17.2 用委托回调静态方法在一个类型中通过委托来调用另一个类型的私有成员,只要委托对象是由具有足够安全性/可访问性的代码创建的,便没有问题。
将方法绑定到委托时,C# 和 CLR 都允许引用类型的协变性(covariance)和逆变性(contravariance)。协变性是指方法能返回从委托的返回类型派生的一个类型。逆变性是指方法获取的参数可以是委托的参数类型的基类。例如下面这个委托:delegate Object MyCallback(FileStream s);完全可以构造该委托类型的一个实例并绑定具有以下原型的方法:String SomeMethod(Stream s);在这里,SomeMethod 的返回类型(String)派生自委托的返回类型(Object);这种协变性是允许的。SomeMethod的参数类型(Stream)是委托的参数类型(FileStream)的基类; ...
第 16 章 数组 本章内容:
初始化数组元素
数组转型
所有数组都隐式派生自 System.Array
所有数组都隐式实现 IEnumerable、ICollection 和 IList
数组的传递和返回
创建下限非零的数组
数组的内部工作原理
不安全的数组访问和固定大小的数组
数组是允许将多个数据项作为集合来处理的机制。CLR 支持一维、多维和交错数组(即数组构成的数组)。所有数组类型都隐式地从 System.Array 抽象类派生,后者又派生自 System.Object。这意味着数组始终是引用类型,是在托管堆上分配的。在应用程序的变量或字段中,包含的是对数组的引用,而不是包含数组本身的元素。下面的代码更清楚地说明了这一点:
12Int32[] myIntegers; // 声明一个数组引用myIntegers = new Int32[100]; // 创建含有 100 个 Int32 的数组
第一行代码声明 myIntegers 变量,它能指向包含 Int32 值的一维数组。myIntegers 刚开始设为 null,因为当时 ...
第 15 章 枚举类型和位标志本章内容:
枚举类型
位标志
为枚举类型添加方法
15.1 枚举类型枚举类型 (enumerated type)定义了一组“符号名称/值”配对。例如,以下 Color 类型定义了一组符号,每个符号都标识一种颜色:
1234567internal enum Color { White, // 赋值 0 Red, // 赋值 1 Green, // 赋值 2 Blue, // 赋值 3 Orange // 赋值 4}
枚举类型是强类型的。例如,将 Color.Orange 作为参数传给要求 Fruit 枚举类型的方法,编译器会报错。
每个枚举类型都直接从 System.Enum 派生,后者从 System.ValueType 派生,而 System.ValueType 又从 System.Object 派生。所以,枚举类型是值类型,可用未装箱和已装箱的形式来表示。但有别于其他值类型,枚举类型不能定 ...
第 14 章 字符、字符串和文本处理本章内容:
字符
System.String类型
高效率构造字符串
获取对象的字符串表示:ToString
解析字符串来获取对象:Parse
编码:字符和字节的相互转换
安全字符串
14.1 字符在.NET Framework 中,字符总是表示成 16 位 Unicode 代码值。每个字符都是System.Char结构(一个值类型)的实例。
14.2 System.String 类型在任何应用程序中,System.String都是用得最多的类型之一。一个 String 代表一个不可变(immutable)的顺序字符集。String类型直接派生自Object,所以是引用类型。因此,String对象(它的字符数组)总是存在于堆上,永远不会跑到线程栈。
14.2.1 构造字符串C# 不允许使用 new 操作符从字面值字符串构造String对象:
12345678using System;public static class Program { public static void Main() { String ...
第 13 章 接口本章内容:
类和接口继承
定义接口
继承接口
关于调用接口方法的更多探讨
隐式和显示接口方法实现(幕后发生的事情)
泛型接口
泛型和接口约束
实现多个具有相同方法名和签名的接口
用显式接口方法实现来增强编译时类型安全性
谨慎使用显式接口方法实现
设计:基类还是接口?
13.1 类和接口继承由于 Microsoft 的开发团队已实现了 Object 的方法,所以从Object派生的任何类实际都继承了以下内容。
方法签名使代码认为自己是在操作Object类的实例,但实际操作的可能是其他类的实例。
方法实现使开发人员定义Object的派生类时不必手动实现Object的方法。
13.2 定义接口如前所述,接口对一组方法签名进行了统一命名。注意,接口还能定义事件、无参属性和有参属性(C# 的索引器)。如前所述,所有这些东西本质上都是方法,它们只是语法上的简化。不过,接口不能定义任何构造器方法,也不能定义任何实例字段。
13.3 继承接口C# 编译器要求将实现接口的方法(后文简称为“接口方法”)标记为 public。CLR 要求将接口方法标记为virtual。不将方法显式 ...
第 12 章 泛型本章内容
FCL 中的泛型
泛型基础结构
泛型接口
泛型委托
委托和接口的逆变和协变泛型类型实参
泛型方法
泛型和其他成员
可验证性和约束
泛型(generic)是 CLR 和编程语言的一种特殊机制,它支持另一种形式的代码重用,即“算法重用”。
CLR 允许创建泛型引用类型和泛型值类型,但不允许创建泛型枚举类型。此外,CLR 还允许创建泛型接口和泛型委托。 CLR 允许在引用类型、值类型或接口中定义泛型方法。
从以上代码可看出泛型为开发人员提供了以下优势。
源代码保护
类型安全
更清晰的代码
更佳的性能
注意 应该意识到,首次为特定数据类型调用方法时,CLR 都会为这个方法生成本机代码。这会增大应用程序的工作集(working set)大小,从而损害性能。
12.1 FCL 中的泛型12.2 泛型基础结构12.2.1 开发类型和封闭类型具有泛型类型参数的类型仍然是类型,CLR 同样会为它创建内部的类型对象。具有泛型类型参数的类型称为开放类型,CLR禁止构造开放类型的任何实例。
为所有类型参数都传递了实际的数据类型,类型就成为封闭类型。C ...
第 11 章 事 件本章内容:
设计公开事件的类型
编译器如何实现事件
设计侦听事件的类型
显式实现事件
11.1 设计要公开事件的类型11.1.1 第一步:定义类型来容纳所有需要发送给事件通知接收者的附加信息11.1.2 第二步:定义事件成员11.1.3 第三步:定义负责引发事件的方法来通知事件的登记对象11.1.4 第四步:定义方法将输入转化为期望事件1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677using System;using System.Threading;namespace ch11{ // 第一步:定义一个类型来容纳所有应该发送给事件通知接受者的附加信息 internal class NewMailEventArgs : EventArgs { private reado ...
第 10 章 属性本章内容:
无参属性
有参属性
调用属性访问器方法时的性能
属性访问器的可访问性
泛型属性访问器方法
CLR 支持两种属性;无参属性,有参属性。
10.1 无参属性将属性想象成智能字段,即背后有额外逻辑的字段。CLR 支持静态、实例、抽象和虚属性。外,属性可用任意“可访问性”修饰符来标记
10.1.1 自动实现的属性如果只是为了封装一个支持字段而创建属性,C#还提供了一种更简洁的语法,称为自动实现的属性(Automatically Implemented Property,后文简称为 AIP)如:
12// 自动实现的属性public String Name { get; set; }
如果使用 AIP,属性必然是可读和可写的。
10.1.2 合理定义属性10.1.3 对象和集合初始化器C# 语言支持一种特殊的对象初始化语法。下面是一个例子:
1Employee e = new Employee() { Name = "Jeff", Age = 45; }
这一行代码等价于以下几行代码。
123Emplo ...
第 9 章 参数本章内容:
可选参数和命名参数
隐式类型的局部变量
以传引用的方式向方法传递参数
向方法传递可变数量的参数
参数和返回类型的设计规范
常量性
9.1 可选参数和命名参数规则和原则如果在方法中为部分参数指定了默认值,请注意以下附加的规则和原则。
可为方法、构造器方法和有参属性(C#索引器)的参数指定默认值。还可以属于委托定义一部分的参数指定默认值。以后调用该委托类型的变量时可省略实参来接受默认值。
有默认值的参数必须放在没有默认值的所有参数之后。“参数数组”这种参数必须放在所有参数(包括有默认值的这些)之后,而且数组本身不能有一个默认值。
默认值必须是编译时能确定的常量值。这些参数的类型可以是C# 认定的基元类型、枚举类型、能设为null的任何引用类型。
不要重命名参数变量
如果方法从模块外部调用,更改参数的默认值具有潜在的危险性。
如果参数用ref或out关键字进行了标识,就不能设置默认值。
实参可按任意顺序传递,但命名实参只能出现在实参列表的尾部。
可按名称将实参传给没有默认值的参数,但所有必须的实参都必须传递(无论按位置还是按名称),编译器才能编译代码。
C# ...










