第二部分 设计类型:第8章 方法

8.1 实例构造器和类(引用类型)

构造器是将类型实例初始化为良好状态的一种特殊方法。.ctor->constructor

创建引用类型的实例过程:
为实例的数据字段分配内存 => 初始化对象的附加字段(类型对象指针、同步块索引) => 调用类型的实例构造器来设置对象的初始状态

实例构造器不能被继承,所以不能将这些修饰符应用于构造器:virtual、new、override、sealed、abstract。

没有显示定义构造器,C#编译器会默认给一个无参的构造器。在它的实现中,只是简单调用基类的无参构造器。

 

•类的修饰符为abstract,编译器生成的默认构造器的可访问性为protected,否则构造器会被赋予public可访问性。
•类的修饰符为static(sealed和abstract),编译器不会在类的定义中生成一个默认构造器。
•如果基类没有提供无参构造器,那么派生类必须显式调用一个基类的构造器,否则编译器会报错。

一个类型可以定义多个实例构造器,每个构造器必须有不同的签名,每个构造器可以有不同的可访问性。(签名:返回值+参数)

类的实例构造器在访问从基类继承的任何字段之前,必须先调用基类的构造器。如果派生类的构造器没有显示调用一个基类构造器,C#编译器会自动生成对默认的基类构造器的调用。最终,System.Object的公共无参构造器会得到调用,该构造器什么都不做直接返回,因为System.Object没有定义实例数据字段,所以它的构造器无事可做。

 

 

8.2 实例构造器和结构(值类型)

 值类型不需要定义构造器。

 出于对性能的考虑,CLR不会为包含在引用类型中的每个值类型字段都调用一个构造器。但值类型的字段会被初始化为0或null。

 

8.3 类型构造器
类型构造器也称为静态构造器、类构造器、类型初始化器。
类型构造器可应用于引用类型、值类型和接口(C#编译器不允许)。

类型构造器的作用是设置类型的初识状态。
类型默认没有定义类型构造器,定义也只能定义一个。类型构造器没有参数。

如何在C#中为引用类型和值类型定义类型构造器:

定义类型构造器必须将它们标记为static,类型构造器总是私有的,c#会自动把它们标记为private,不能人为添加访问修饰符。

 

 

 

 8.4操作符重载方法

CLR对操作符一无所知。至于CRL,操作符重载只是方法而已。

编译源码时,编译器会生成一个标识操作符行为的方法。CLR规范要求操作符重载方法必须是public和static方法。另外,C#(以及其他许多语言)要求操作符重载方法至少有一个参数的类型和当前定义这个方法的类型相同。为了使C#编译器能在合理的时间内找到要绑定的操作符方法。

 

 操作符和编程语言互操作性
使用不支持操作符重载的编程语言时,语言应该允许你直接调用希望的op_*方法(例如 op_Addition)。

 

8.5 转换操作符方法

当源类型和目标类型都是编译器的基元类型时,编译器自己就知道如何生成转换对象所需要的代码(如:Tyte=>Int32)。

如果源类型或目标类型不是基元类型,编译器会生成代码,要求CLR执行转换(强制转型)。这时,CLR只是检查源对象的类型和目标类型(或者从目标类型派生的其他类型)是不是相同。

将对象从一个类型转换成一个完全不同的类型,如:System.Xml.Linq.XElement=>Boolean

假设FCL包含了Rational(有理数)类型,将Int32或Single转换成Rational。
Rational类型应该定义只有一个参数的公共构造器,这个参数是源类型的一个实例。还应该定义无参数的公共实例方法ToXxx(和普遍使用的ToString方法相似),每个方法都将定义类型的一个实例转换成Xxx类型。

在C#中,implicit关键字告诉编译器为了生成代码来调用方法,不需要在源代码中进行显示转换。相反,explicit只有发现了显示转型时,才调用方法。

在implicit或explicit关键字后,要指定operator关键字告诉编译器该方法是一个转换操作符。在operator之后,指定对象要转换成什么类型。在圆括号内,则指定要从什么类型转换。

 

8.6 扩展方法

扩展方法它允许你定义一个静态方法,并用实例方法的语法来调用它。

 

8.6.1 规则和原则
•C#只支持扩展方法,不支持扩展属性、事件、操作符等。
•扩展方法(第一个参数前面有this的方法)必须在非泛型的静态类中声明。
 类名没有限制,扩展方法至少有一个参数,而且只有第一个参数能用this关键字标记。
•C#编译器查找静态类中定义的扩展方法时,要求这些静态类本身必须具有文件作用域。
 如果静态类嵌套在另一个类中,C#编译器会显示:error CS1109:扩展方法必须在顶级静态类中定义;

8.6.2 用扩展方法扩展各种类型
由于扩展方法实际是对一个静态方法的调用,所以CLR不会生产代码对调用方法的表达式的值进行null值检查(不保证它非空):

8.6.3 ExtensionAttribu类
在C#中,一旦用this关键字标记了某个静态方法的第一个参数,编译器就会在内部向该方法应用一个定制attribute。这个attribute会在最终生产的文件的元数据中持久性地存储下来。这个attribute是在System.Core.dll程序集中定义的。

除此之外,任何静态类只要包含了至少一个扩展方法,它的元数据中也会应用这个attribute。类似地,任何程序集只要包含了至少一个符合上述特点的静态类,它的元数据中也会应用这个attribute。这样一来,如果代码调用了一个不存在的实例方法,编译器就会快速扫描引用的所有程序集,判断它们哪个包含了扩展方法。然后,在这些程序集中,可以只扫描包含了扩展方法的静态类,可以只扫描扩展方法来查找匹配。利用这个技术,代码可以快速的编译完成。

 

 8.7 分部方法

规则和原则
•它们只能在分部类或结构中声明。
•分布方法的返回类型始终是void,任何参数都不能用out修饰符来标记。之所以有这两个限制,是因为方法在运行时可能不存在,所以不能将一个变量初始化为方法也许会返回的东西。之所以不能有out参数,是因为方法必须初始化它,而这个方法可能是不存在的。分部方法可以有ref参数,可以是泛型方法、实例或静态方法,而且可标记为unsafe。
•分部方法的声明和实现必须具有完全一致的签名。如果两者都应用了定制attribute,编译器会将两个方法的attribute合并到一起。应用于参数的任何attribute也会合并。
•如果没有对应的实现部分,便不能在代码中创建一个委托来引用这个分部方法。同样,这是由于方法在运行时不存在。编译器会报告以下消息:error CS0762:无法通过方法“XX”创建委托,因为该方法是没有实现声明的分部方法。
•分部方法总被视为private方法。但是,C#编译器禁止你在分部方法声明之前添加private关键字。

 

posted @ 2014-04-02 14:15  IT浪潮之巅  阅读(109)  评论(0编辑  收藏  举报
   友情链接: 淘宝优惠券