10.C#基础之类(在整理当中)

     类——一种数据结构,前面提到过很多次,这次就详细写一下。类可以包含数据成员(常数和字段)、函数成员(方法、属性、事件、索引器、运算符、实例构造函数、静态构造函数、析构函数),以及嵌套类型。类类型支持继承,继承是一种机制,使得派生类可以对基类进行扩展和专用化。

  10.1类声明

     类声明是一种类型声明,用于声明一个新的类。

     上面这两个图就是类声明的组成方式:先是一组可选的特性,后跟可选的类修饰符,接着是关键字class和用来命名该类的标识符(即该类的名字),然后是可选的类基规范,最后是类体,后面可能接着一个分号。

   10.1.1 类修饰符

     new修饰符:适用于嵌套类,它表示所修饰的类会把继承下来的同名成员隐藏起来。若new出现在类声明中,却又不是一个嵌套类声明,会导致编译时错误。

     public、protected、internal、private修饰符是控制类的可访问性,第三章具体写过,这里不多写了。

     abstract修饰符:表示所修饰的类是不完整的,并且它只能用做基类,且用它修饰的类被称为抽象类。抽象类不能直接实例化,并且对抽象类使用new运算符会导致编译时错误。当抽象类派生出非抽象类时,非抽象类必须具体实现继承的所有抽象类成员。

     sealed修饰符:用于防止所修饰的类派生出其他类,所以也被称为密封类。密封类不能为抽象类。

   10.1.2 类基规范

     类基规范:定义了该类的直接基类和由该类实现的接口。

     如果类声明中没有类基,或所含的类基只列出接口类型,那就设定直接基类是object,类会从它的直接基类继承成员。类类型的直接基类必须至少与该类具有同样的可访问性,如果试图从private类派生一个public类,就会导致编译时错误。

     类的基类包括它的直接基类和直接基类的基类。可以说基类集是直接基类关系的传递闭包。比如:class A{}    class B:A{}   B的基类是A和object。

   10.1.3 类体

     类体:用于定义该类的成员。

  10.2类成员

     类成员分两部分组成:自己声明引入的成员和从直接基类继承来的成员。

         常数:表示与该类相关联的常数值;

         字段:该类的变量;

         方法:实现由该类执行的计算和操作;

         属性:用于定义一些命名特性,以及与读取和写入这些特征相关的行为;

         事件:用于定义可由该类生成的通知;

         索引器:使该类的实例可按与数组相同的方式进行索引;

         运算符:用于定义表达式运算符,通过它对该类的实例进行运算;

         实例构造函数:用于规定在初始化该类的实例时需要做什么;

         析构函数:用于规定在永远地放弃该类的实例之前需要做什么;

         静态构造函数:用于规定在初始化该类自身时需要做什么;

         类型:用于表示一些类型,它们是该类的局部类型。

     可包含可执行代码的成员统称为该类的函数成员。类的函数成员包括:方法、属性、事件、索引器、运算符、实例构造函数、析构函数、静态构造函数。

     类声明将创建新的声明空间,而直接在该类声明内的类成员声明将在此声明空间引入新成员:

         实例构造函数、析构函数和静态构造函数必须具有和直接封闭它们的类同样的名称,其他的成员的名称必须和该类的名称不同;

         常数、字段、属性、事件或类型的名称必须不同于在同一个类中声明的其他成员的名称;

         方法的名称必须和其他在同一个类声明的所有非方法的名称不同,此外方法的签名也不能和其他方法相同;

         实例构造函数、索引器和运算符的签名必须不同于同一类的其他所有的实例构造函数、索引器和运算符。

     注:类的继承成员不再类的声明空间的组成部分,所以派生类可以使用同样的名称或签名来声明自己的新成员,同时隐藏被继承的同名成员。

   10.2.1 继承

     类继承它的直接基类的成员。继承以为着隐式地把它的直接基类的所有成员当做自己的成员,当然除了基类的实例构造、静态构造和析构函数除外。

         继承是可传递的。比如A派生B,B又派生C,那么C就会继承A、B中的声明成员;

         派生类扩展它的直接基类,可以向它继承的成员添加新成员,但不能移除继承成员的定义;

         除了上面说的3个例外,所有都可被继承,但有的可能不能被访问,这就和访问性有关了;

         类可以声明虚拟方法、属性和索引器,而派生类可以重谢它们的实现,这就展示了多态特征。

   10.2.2 new修饰符

     类成员声明中可以使用与一个被继承的成员相同的名称或签名来声明一个成员,这就称该派生类成员隐藏了基类成员。隐藏不算错误,但会发出警告,这时就可以在派生类成员的声明中包含一个new修饰符,表示有意隐藏基类成员就可以了。

   10.2.3 访问修饰符

     类成员的访问性可以有五种:public、protected internal、protected、internal和private,默认时是private。

   10.2.4 静态成员和实例成员

     类的成员要么是静态成员,要么就是实例成员。静态成员属于类,实例成员属于对象(即类的实例)。

     当字段、方法、属性、事件、运算符和构造函数声明中含有static修饰符时,就是声明了静态成员。常数和类型会隐式地声明为静态成员;当没有static修饰符时,就是实例成员。

   10.2.6 嵌套类型

     在类或结构内声明的类型称嵌套类型;在编译单元或命名空间声明的类型是非嵌套类型。比如:

     类B就是嵌套类型,因为它声明在A中;相对A就是非嵌套类型。嵌套类型的完全限定名为S.N,比如上面的B的完全限定名就是:A.B。

     非嵌套类型只能具有2个访问类型,public、internal,默认是internal。

   10.2.7 保留成员名称

     为了便于底层的C#运行库的实现,对于每个属性、事件或索引器的源成员声明,任何一个实现都必须根据该成员声明的种类、名称和类型保留两个方法签名。如果程序声明一个成员,而该成员的签名与这些保留签名中的某一个匹配,那么即使所使用的底层运行库的实现并没有使用这些保留签名,但仍会导致一个编译时错误。

     保留名称不会引入声明,因此它们不参与成员查找。但是,一个声明若具有相关联的保留方法签名,则该方法签名会参与继承,也可以被隐藏。保留这么名称的目的:

         1.使基础的实现可以通过将普通标识符用做一个方法名称,对C#语言功能进行get或set访问;

         2.使其他语言可以通过将普通标识符用做一个方法名称,对C#语言功能进行get或set访问,从而实现交互操作;

         3.使保留成员名称的细节在所有C#实现中保持一致,这有助于确保被一个符合本规范的编译器所接受的源程序也可被另一个编译器接受。

     对于类型T的属性P,保留了下列签名:

     对于委托类型T的事件E,保留了下列签名:

     对于类型T的具有参数列表L的索引器,保留了下列签名:

     对于包含析构函数的类,保留了下列签名:

  10.3常数

     常数是类成员,表示一个常数值(可以在编译时计算的值)。常数声明可以引入一个或多个给定类型的常数:

     虽然常数被认为是静态成员,但在常数声明中即不要求也不允许使用static修饰符。

     常数声明中指定的类型必须是sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal、bool、string、枚举类型或引用类型。每个常数表达式所产生的值,必须属于目标类型的,或者可以通过隐式转换转换为目标类型。

     如果需要一个具有常数值的符号名称,但该值的类型不允许在常数声明中使用,或在编译时无法有常数表达式计算出该值,则可以改用readonly字段。

  10.4字段

     字段:是一种表示与对象或类关联的变量的成员。

   10.4.1 静态字段和实例字段

     当字段声明中含有static修饰符时,由该声明引入的字段为静态字段;当不存在时,由该声明引入的字段为实例字段。静态字段和实例字段是C#所支持的几种变量中的两种,它们有时被分别称为静态变量和实例变量。

   10.4.2 只读字段

     当字段声明中还有readonly修饰符时,该声明所引入的字段为只读字段。给只读字段的直接赋值只能作为声明的组成部分出现,或在同一类的实例构造函数或静态构造函数中出现;对于实例字段,在包含字段声明的类的实例构造函数中,对于静态字段,在包含字段声明的类的静态构造函数中,将readonly字段作为out或ref参数传递才有效。

     静态只读字段:需要一个具有常数值的符号名称,但该值的类型不允许在const声明中使用,或这无法在编译时计算出该值,则static readonly字段就可以发挥作用了。比如:

     其中,Black、White、Red、Green、Blue成员不能被声明为const成员,这是因为编译时无法计算它们的值。

     常数和只读字段具有不同的二进制版本控制语义。当表达式引用常数时,该常数的值在编译时获取,但当表达式引用只读字段时,要等到运行时才获取该字段的值。比如:

     Program1和Program2命名空间表示两个单独编译的程序。由于Program1.Utiles.X声明为静态只读字段,因此Consele.WriteLine语句要输出的值在编译时是未知的,在运行时才能获取。如果更改X的值并重新编译Program1,则即使Program2未被重新编译,Consele.WriteLine语句也将输出新值。但如果X是常数,那么X的值将在编译Program2时获取,并且在重新编译Program2之前不会受到Program1中的更改的影响。

   10.4.3 易失字段

     当字段声明中含有volatile修饰符时,该声明引入的字段为易失字段。

     由于采用了优化技术(它会重新安排指令的执行顺序),在多线程的程序运行环境下,如果不采取同步控制手段,则对于非易失字段的访问可能会导致意外的和不可预见的结果。这些优化可以由编译器、运行时系统或硬件执行。但对于易失字段,优化时的这种重新排序必须遵循以下规则:

         1.读取一个易失字段称为易失读取。易失读取具有"获取语义",也就是说,按照指令序列,所有排在易失读取之后的对内存的引用,在执行时也一定排在它的后面;

         2.写入一个易失字段称为易失写入。易失写入具有"释放语义",也就是说,按照指令序列,所有排在易失写入之前的对内存的引用,在执行时也一定排在它的面前。

     这些限制能确保所有线程都会观察到由其他任何线程所执行的易失写入(按照原来安排的顺序)。一个遵循本规范的实现并非必须要使易失写入的执行顺序,在所有正在执行的线程看来都是一样的。易失字段的类型必须时下列类型中的一种:

         引用类型;

         类型byte,sbyte,short,ushort,int,uint,char,float或bool;

         枚举基类型为byte,sbyte,short,ushort,int或uint的枚举类型。

   10.4.4 字段初始化

     字段的初始值都是字段的类型的默认值。在此默认初始化发生之前是不可能看到字段的值的,因此字段永远不会是"未初始化的"。比如:

     这是因为b和i都被自动初始化为默认值。

   10.4.5 变量初始值设定项

     字段声明可以包含变量初始值设定项。对于静态字段,变量初始值设定项相当于在类初始化期间执行的赋值语句;对于实例字段,变量初始值设定项相当于创建类的实例时执行的赋值语句。

  10.5方法

     发

猜你喜欢

转载自www.cnblogs.com/dreamoffire/p/10098522.html