6.深入理解类

目录

6.1 类成员

6.2 成员修饰符的顺序

6.3 实例类成员

 6.4 静态字段

 6.5 从类的外部访问静态成员

6.5.1 静态字段实例

6.5.2 静态成员的生存期

6.6 静态函数成员

6.7 其他静态类。成员类型

6.8 成员常量

6.9 常量与静态量

​ 6.10 属性

6.10.1 属性声明和访问器

6.10.2 属性示例

6.10.3 使用属性

 6.10.4 属性和关联字段

6.10.5 执行其他计算

 6.10.6 只读和只写属性

6.10.7 属性与公共字段

6.10.8 计算只读属性示例

 6.10.9 自动实现属性

6.10.10 静态属性

 6.11 实例构造函数

6.11.1 带参数的构造函数

6.11.2 默认构造函数

6.12 静态构造函数

静态构造函数实例

6.13 对象初始化语句

​ 6.14 析构函数

6.15 readonly修饰符

 6.16 this 关键字

6.17 索引器

6.17.1 什么是索引器

 6.17.2 索引器和属性

6.17.3 声明索引器

6.17.4 索引器的set访问器

6.17.5 索引器的get访问器

6.17.6 关于索引器的补充

6.17.7 为Employee示例声明索引器

6.17.8 另一个索引器的实例

6.17.9 索引器重载

6.18 访问器的访问修饰符

6.19 分布类和分布类型

6.20 分部方法


6.1 类成员

之前的两章阐述了9中类成员类型的两种:字段和方法。在这一章中,我会介绍除事件和运算符之外的类型的类成员,并讨论其特征。我会在14章介绍事件。

表6-1列出了类的成员类型。已经介绍过的类型用菱形标记。将在本章阐述的类型用勾号标记,将在以后的章节阐述的类型用空的选择框标记。

6.深入理解类_第1张图片

6.2 成员修饰符的顺序

在前面的内容中,你看到字段和方法的声明可以包括public和private这样的修饰符。这一章会讨论许多其他的修饰符。多个修饰符可以在一起使用,自然就产生了一个问题:它们需要按什么顺序排列呢?

类成员声明语句由下部分组成:核心声明、一组可选的修饰符和一组可选的特性(attribute)。用于描述这个结构的语法如下。方括号表示方括号内的成分是可选的。

【特性】【修饰符】 核心声明

  • 修饰符
  1. 如果有修饰符,必须放在核心声明之前。
  2. 如果有多个修饰符,可以是任意顺序。
  • 特性
  1. 如果有特性,必须放在修饰符和核心声明之前。
  2. 如果有多个特性,可以是任意顺序。

至此,我直解释两个修饰符,及public和private 。在第24章中我会在介绍特性。

例如,public和static都是修饰符,可以用来一起修饰某个声明。因为它们都是修饰符,所以可以放置成任何顺序。下面两行代码语义等价:

6.深入理解类_第2张图片 

6.3 实例类成员

类成员可以关联到类的一个实例,也可以关联到类的整体,既所有类的实例。默认情况下,成员被关联到一个实例。可以认为是类的每个实例拥有自己的各个类成员的副本,这些成员称为实例成员。

改变一个实例字段的值不会影响任何其他实例中成员的值。迄今为止,你所看到的字段和方法都是实例字段和实例方法。

例如,下面的代码声明了一个类D,它带有唯一整形字段Mem1.Main创建了该类的两个实例,每个实例都有自己的字段Mem1的副本,改变一个实例的字段副本的值不影响其他实例的副本的值。图6-2阐明了类D的两个实例、

6.深入理解类_第3张图片 

6.深入理解类_第4张图片 

 6.4 静态字段

除了实例字段,类还可以,拥有静态字段。

  • 静态字段被类的所有实例共享,所有实例都访问同一内存位置。因此,如果该内存位置的值被一个实例改变了,这种改变对所有的实例都可见。
  • 可以使用static修饰符将字段声明为静态,如:

例如,图6-3左边的代码声明了类D,它含有静态字段Mem2和实例字段Mem1.Main定义了类D的两个实例。该图表明静态成员Mem2是与所有实例存储分开保存的。实例中灰色字段表明。从实例内部,访问或更新静态字段的语法和访问或更新其他成员字段一样。

  • 因为Mem2是静态的,类D的两个实例共享单一的Mem2字段。如果Mem2被改变了,这个改变在两个实例中都能看到。
  • 成员Mem1没有声明为static,所以每个实例都有自己的副本。

6.深入理解类_第5张图片 

 6.5 从类的外部访问静态成员

在前一章中,我们看到使用点运算符可以从类的外部访问public实例成员。点运算符由实例名、点和成员组成。

就像实例成员,静态成员也可以使用点运算符从类的外部访问。但因为没有实例,所以必须使用类名,如下面代码所示:

6.5.1 静态字段实例

下面的代码扩展了前文的类D,增加了两个方法: 

  • 一个方法设置了两个数据成员的值。
  • 另一个方法显示两个数据成员的值。

6.深入理解类_第6张图片

6.5.2 静态成员的生存期

静态成员的生命周期与实例成员的不同。

  • 之前我们已经看到了,只有在实例创建之后才产生实例成员,在实例销毁之后实例成员也就不复存在了。
  • 但是即使类没有实例,也存在静态成员,并且可以访问。 

6.深入理解类_第7张图片

6.6 静态函数成员

除了静态字段,还有静态函数成员。

  • 如同静态字段,静态函数成员独立与任何类实例。即使没有类的实例,仍然可以调用静态方法。
  • 静态函数成员不能访问实例成员。然而它们能访问其他静态成员。

例如,下面的类包含一个静态字段和一个静态方法。注意,静态方法的方法体访问静态字段。

6.深入理解类_第8张图片

6.深入理解类_第9张图片

6.7 其他静态类。成员类型

可以声明为static的类成员类型在表6-2中做了勾选标记。其他类型成员不能声明为static。 

6.深入理解类_第10张图片

6.8 成员常量

成员常量类似前一章所述的本地常量,只是它们被声明在类声明中而不是方法内,如下面的实例: 

6.深入理解类_第11张图片

6.9 常量与静态量

然而,成员常量比本地常量更有趣,因为它们表现得像静态值。它们对类的每个实例都是“可见的”,而且即使没有类的实例也可以使用。与真正的静态量不同,常量没有自己存储位置,而是在编译时被编译器替换。这种方式类似于C和C++中的#define值。

例如,下面的代码声明了类X,带有常量字段PI。Main没有创建任何实例,但仍然可以使用字段PI并打印它的值。图6-6阐明了这段代码。

 

6.深入理解类_第12张图片 6.10 属性

属性是代表类实例或类中的一个数据项的成员。使用属性看起来非常像写入或读取一个字段,语法是相同的。

例如,下面的代码展示了名称为MyClass的类的使用,它有一个公有字段和一个公有属性。从用法上无法区分它们。

 与字段类似,属性有如下特性。

  • 它是命名的类成员。
  • 它有类型。
  • 它可以被赋值和读取。

然而和字段不同,属性是一个函数成员。

  • 它不为数据存储分配内存!
  • 它执行代码。

属性是定的一组两个匹配的、称为访问器的方法。

  • set访问器为属性赋值。
  • get访问器从属性获取值。

图6-7展示了属性的表示法。左边的代码展示了声明一个名称为MyValue的int型属性的语法,右边的图像展示了属性在文本中将如何可视化地显示。请注意,访问器被显示为从后面伸出,因为它们不能直接被调用。这一点你很快就会看到。

6.深入理解类_第13张图片

6.10.1 属性声明和访问器

set和get访问器有预定义的语法和语义。可以把set访问器想象成一个方法,带有单一的参数“设置”属性的值。get访问器没有参数并从属性返回一个值。

  • set访问器总是:
  1. 拥有一个单独的、隐式的值参、名称为value,与属性的类型相同;
  2. 拥有一个返回类型void。
  • get访问器总是:
  1. 没有参数;
  2. 拥有一个与属性类型相同的返回类型。

属性声明结构如图6-8所示。注意,图中访问器声明既没有显示的参数,也没有返回类型声明。不需要它们,因为它们已经在属性的类型中隐含了。

6.深入理解类_第14张图片

set访问器中的隐式参数value是一个普通的值参。和其他值参一样,可以用它发送数据到方法或这种情况的访问器块。在块的内部,可以像普通变量使用value,包括对它赋值。

访问器的其他终点如下。

  • get访问器的所有执行路径必须包含一条return语句,返回一个属性类型的值。
  • 访问器set和get可以以任何顺序声明,并且,除了两个访问器外在属性上不允许有其他方法。

6.10.2 属性示例

下面的代码展示了一个名为C1的类的声明示例,它含有一个名称为MyValue的属性。

  • 请注意属性本身没有任何存储。取而代之的是,访问器决定如何处理发进来的数据,以及蛇什么数据应该被发送出去。在这种情况下,属性使用一个名称为TheReaIValue的字段作为存储。
  • set访问器接受它的输入参数value,并把它的值赋给字段TheRealValue。
  • get访问器只是返回字段TheRealValue的值。

图6-9说明了这段代码。

6.深入理解类_第15张图片 

6.深入理解类_第16张图片 

6.10.3 使用属性

就像之前看到的,写入和读取属性的方法与访问字段一样。访问器被隐式调用。

  • 要写入一个属性,在赋值语句的左边使用属性的名称。
  • 要读取一个属性,把属性的名称用在表达式中。

例如,下面的代码包含一个名称为MyValue的属性声明的轮廓。只使用属性名写入和读取属性,就好像它是一个字段名。

6.深入理解类_第17张图片 

 6.10.4 属性和关联字段

属性常和字段关联,我们在前两节已经看到了。一种常见的方式是在类中将字段声明为private以封装该字段,并声明一个public属性来控制从类的外部对该字段的访问。和属性关联的字段常被称为后备字段或后备存储。

6.深入理解类_第18张图片

属性和它们的后备字段有几种命定约定。一种约定是两个名称使用相同的内容,但字段使用Camel大小写,属性使用Pascal大小写,(在Canel大小写风格中,复合台词标识符中每个单词的首字母都是大写。)虽然这违反了“仅使用大小写区不同的标识符是个坏习惯”这条一般规则,但它有个好处,可以把两个标识符以一种有意义的方式联系在一起。

另一种约定是属性使用Pascal大小写,字段使用相同标识符的Camel大小写版本。并以下划线开始。下面的代码展示了两种约定:

6.深入理解类_第19张图片 

6.10.5 执行其他计算

属性访问器并不局限于仅仅对关联的后备字段进行传出数据。访问器get和set能执行任何计算,或不执行任何计算。唯一必需的行为是get访问器要返回一个属性类型的值。

例如,下面的示例展示了一个有效的(但可能没有用的)属性,仅在get访问器被调用时返回5.当set访问器被调用时,它不做任何事情。隐式参数value的值被忽略了。 

6.深入理解类_第20张图片

 6.10.6 只读和只写属性

要想不定义属性的某个访问器,可以忽略该访问器的声明。

  • 只有get访问器的属性称为只读属性。只读属性是一种安全的,把一项数据从类或类的实例中传出,而不允许太多访问方法。
  • 只有set访问器的属性被称为只写属性。只写属性是一种安全的,把一项数据从类的外部传入类,而不允许太多访问的方法。
  • 两个访问器中至少有一个必须定义,否则编译器会产生一条错误信息。

6.深入理解类_第21张图片

6.10.7 属性与公共字段

按照推荐属性的编码实践,属性比公共字段更好,理由如下。

  • 属性是函数型成员而不是数据成员,允许你处理输入和输出,而公共字段不行。
  • 属性可以只读或只写,而字段不行。
  • 编译后的变量和编译后的属性语义不同。

如果要发布一个由其他代码引用的程序集,那么第二点将会带来一点影响。例如,有时候开发人员会有公共的字段代替属性的冲动,因为如果以后需要字段的数据增加处理逻辑的话可以再把字段改为属性。这没错,但是如果那样修改的话,所有访问这个字段的其他程序集都需要重新编译,因为字段和属性在编译后的语义不一样。另外,如果实现的属性,那么只需要修改属性的实现,无需重新编译访问它的其他程序集。

6.10.8 计算只读属性示例

迄今为止,在大多数示例中,属性都和一个后备字段相互关联,并且get和set访问器引用该字段。

然而,属性并非必须和字段关联。在下面的实例中,get访问器计算出返回值。

在下面的示例中,类RightTriangle自然而然的表示一个直角三角形。图6-11阐述了只读属性Hypotenuse。

  • 它有两个公共字段,表示直角三角形的两条直角边的长度。这些字段可以被写入和读取。
  • 第三边有属性Hypotenuse表示,它只是一个只读属性,并返回值基于另外两条边的长度。它没有储存在字段中。相反,它在需要时根据当前A和B的值计算正确的值。

6.深入理解类_第22张图片

 6.深入理解类_第23张图片

 6.10.9 自动实现属性

因为属性经常被关联到后备字段,C#提供了自动实现属性,允许只声明属性而不声明后备字段。编译器会为你创建隐藏后备字段;并且自动连接到get和set访问器上。

自动实现属性的要点如下。

  • 不声明后备字段------编译器根据属性的类型分配内存。
  • 不能提供访问器的方法体-------他们必须被简单地声明为分号。get担当简单的内存读,set担当简单的写。
  • 除非通过访问器,否则不能访问后备字段。因为不能用其他的方法访问它,所以实现只读和只写属性没有意义,因此必须同时提供读写访问器。

下面的代码展示了一个自动实现属性的示例。

6.深入理解类_第24张图片

6.深入理解类_第25张图片 

6.10.10 静态属性

属性也可以声明为static。静态属性的访问器何所有静态成员一样,具有以下特点。

  •  不能访问类的实例成员--------虽然它们能被实例成员访问。
  • 不管类是否有实例,它们都是存在的。
  • 当从类的外部访问时,必须使用类名引用,而不是实例名。

例如,下面的代码展示了一个类,它带有名称为MyValue的自动实现的静态属性。在Main的开始三行,即使没有类的实例,也能访问属性。Main的最后一行调用一个实例方法。它从类的内部访问属性。

6.深入理解类_第26张图片

6.深入理解类_第27张图片 6.11 实例构造函数

实例构造函数是一个特殊的方法,在它创建类的每个新实例时执行。

  • 构造函数用于初始化类实例的状态。
  • 如果希望能从类的外部创建类的实例,需要将构造函数声明为public。

图6-12阐述了构造函数的语法。除了下面的这几点,构造函数看起来很像类声明中的其他方法。

  • 构造函数的名称和类名相同。
  • 构造函数不能有返回值。

6.深入理解类_第28张图片

例如,下面的类使用构造函数初始化字段。本例中,它有一个名称为TimeOfInstantiation的字段被初始化为当前日期和时间。

6.深入理解类_第29张图片 

6.11.1 带参数的构造函数

构造函数在下列方面和其他方法相似。

  • 构造函数可以带参数。参数的语法和其他方法完全相同。
  • 构造函数可以被重载。

在使用创建对象表达式创建类的新实例时,要使用new运算符,后面跟着4类的某个构造函数。new运算符使用该构造函数创建类的实例。

例如,在下面的代码中,Class1有3个构造函数:一个不带参数,一个带int参数,一个带string参数。Main使用各个构造函数创建实例。

6.深入理解类_第30张图片

 

6.11.2 默认构造函数

如果再类的声明中没有显示地提供实参构造函数,那么编译器会提供一个隐式的默认构造函数,它有以下特征。 

  • 没有参数。
  • 方法体为空。

如果你为类声明了任何构造参数,那么编译器将不会为该类定义默认构造函数。

例如,下面的代码中Class2声明了两个构造函数。

  • 因为已经至少有一个显示定义的构造函数,编译器不会创建爱任何额外的构造函数。
  • 在Main中,试图使用不带参数的构造函数创建新的实例、因为没有无参数的构造函数,所以编译器会产生一条错误信息。

6.深入理解类_第31张图片

6.12 静态构造函数

构造函数也可以声明为static。实例构造函数初始化类的每个新实例。而static构造函数初始化类级别的项。通常,静态构造函数初始化类静态字段。

  • 初始化类级别的项。
  1. 在引用任何静态成员之前。
  2. 在创建类的任何实例之前。
  • 静态构造函数在以下方面与实例构造函数类似。
  1. 静态构造函数的名称必须和类名相同。
  2. 构造函数不能返回值。
  • 静态构造函数在以下方面和实例构造函数不同
  1. 静态构造函数声明中使用static关键字。
  2. 类只能有一个静态构造函数,而不能带参数。
  3. 静态构造函数不能有访问修饰符。

下面是一个静态构造函数的实例。注意其形式和构造函数相同,只是增加了static关键字。

6.深入理解类_第32张图片

关于静态构造函数应该了解的其他重要内容如下。

  • 类既可以有静态构造函数也可以有实例构造函数。
  • 如同静态方法,静态构造函数不能访问所在类的实例成员,因此也不能使用this访问器,我们马上会讲述这一内容。
  • 不能从程序中显示调用静态构造函数,系统会自动调用它们,在:
  1. 类的任何实例被创建之前;
  2. 类的任何静态成员被引用之前。

静态构造函数实例

 下面的代码使用静态构造函数初始化一个名称为RandomKey的Random型私有静态字段。Random是有BCL提供的用于产生随机数类,位于System命名空间中。 

6.深入理解类_第33张图片

6.深入理解类_第34张图片 

6.13 对象初始化语句

再次之前的内容中你已经看到,对象创建表达式有关键字new后面跟着一个类构造函数及其参数列表组成。对象初始化语句扩展创建语法,在表达式的尾部放置了一组成员初始化语句。这允许你在创建新的对象实例时,设置字段和属性的值。

该语法有两种形式,如下面所示。一种形式包括构造函数的参数列表,另一种不包括。注意,第一种形式甚至不使用括起参数列表的圆括号。

6.深入理解类_第35张图片 

 例如,对于一个名称为Point类,它有两个公有整形字段X和Y,你可以使用下面的表达式创建一个新对象:

关于对象初始化语句要了解的重要内容如下。

  • 创建对象的代码必须能够访问要初始化的字段和属性。例如,在之前的代码中X和Y必须是public的。
  • 初始化发生在构造方法执行之后,因此在构造方法中设置的值可能会在之后对象初始化中重置为相同或不同的值。

下面的代码展示了一个使用对象初始化语句的实例。Main中,pt1只调用构造函数,构造函数设置了它的两个字段的值。然而,对于pt2,构造函数把字段的值设置为1和2,初始化语句把他们改为5和6.

6.深入理解类_第36张图片 6.14 析构函数

析构函数(destructor)执行在类的实例被销毁之前需要的清理或释放非托管资源的行为。非托管资源是指通过Win32 API获得的文件句柄,非托管内存块,使用.NET资源是无法得到他们的,因此如果坚持使用.NET类,就不需要为类编写析构函数。因此,我们等到第25章再来描述析构函数。

6.15 readonly修饰符

字段可以用readonly修饰符 ,其作用类似于将字段声明为const,一旦值被设定就不能改变。

  • const字段只能在字段的声明语句中初始化,而readonly字段的值可以在运行时决定,这种增加的自由行允许你在不同的环境或不同的构造函数中设置不同的值!
  • 和const,const的行为总是静态的,而对于readonly字段以下两点是正确的。
  1. 它可以是实例字段,也可以是静态字段。
  2. 它在内存中有存储位置。

例如,下面的代码声明了一个名称为Shape的类,它有两个readonly字段。

  • 字段PI在它的声明中初始化。
  • 字段NumberOfSides根据调用的构造函数被设置为3或·4.

6.深入理解类_第37张图片

 

 6.16 this 关键字

this关键字在类中使用,是对当前实例的引用。它只能被用在下列类成员的代码块中。

  • 实例构造函数。
  • 实例方法。
  • 属性和索引器的实例访问器(索引将在下一节阐述)。

很明显,因为静态成员不是实例的一部分,所以不能在任静态函数成员的代码中使用this关键字。更适当地说,this用于下列目的:

  • 用于区分类的成员和本地变量或参数;
  • 作为调用方法的实参。

例如,下面的代码声明了类Myclass,他有一个int字段和一个方法,方法带有一个单独的int参数。方法比较参数和字段的值并返回其中较大的值。唯一的问题是字段和形参的名称相同,都是var1.在方法内使用this关键字引用字段,以区分这两个名称。注意,不推荐参数和类型的字段使用相同的名称。

6.深入理解类_第38张图片

6.17 索引器

假设我们要定义一个类Employee,它带有3个string型字段(如图6-13所示),那么可以使用字段的名称访问它们,如Main中的代码所示。 

6.深入理解类_第39张图片

然而有的时候,如果能使用索引访问它们将会很方便,好像该实例是字段的数组一样。这正是索引器允许做的事。如果为类Employee写一个索引器,方法Main看起来就像是图6-14中的代码那样。谁注意没有使用点运算符,相反,索引器使用索引运算符,他由一对方括号和中间的索引组成。

6.深入理解类_第40张图片 

6.17.1 什么是索引器

索引器是一组get和set访问器,与属性类似。图6-15展示了一个类的索引器的表现形式,该类可以获取和设置string型的值。

6.深入理解类_第41张图片

 6.17.2 索引器和属性

索引器和属性在很多地方是相似的。

  • 和属性一样,索引器不用分配内存来存储。
  • 索引器和属性都主要被用来访问其他数据成员,它们与这些成员关联,并为它们提供获取和设置访问。
  1. 属性通常表示单独的数据成员。
  2. 索引器通常表示多个数据成员。

关于索引器,还有一些注意事项如下。

  • 和属性一样,索引器可以只有一个访问器,也可以两个都有。
  • 索引器总是实例成员。因此不能声明为static。
  • 和属性一样,实现get和set访问器的代码不必一定要关联到某个字段和属性。这段代码可以做任何事情或什么也不做,只要get访问器返回某个指定类型的值即可。

6.17.3 声明索引器

声明索引器的语法如下。请注意以下几点。

  • 索引器没有名称。在名称的位置是关键字this。
  • 参数列表在方括号中间。
  • 参数列表中必须至少声明一个参数。

6.深入理解类_第42张图片

6.17.4 索引器的set访问器

当索引器被用于赋值时,set访问器被调用,并接受两项数据,如下:

  • 一个隐式参数,名称为value,value持有要保持的数据;
  • 一个或更多索引参数,表示数据应该保存到哪里。

 

在set访问器中的代码必须检查索引参数,已确定数据应该存往何处,然后保存它。

set访问器的语法和含义如图6-17所示。图的左边展示了访问器声明的实际语法。右边展示了访问器的语义,把访问器的语法以普通方法的语法书法写出来。右边的图例表明set访问器有如下语义。

  •  它的返回类型为void。
  • 它使用的参数列表和索引器声明中的相同。
  • 它有一个名称为value的隐式参数,值参类型和索引类型相同。

6.深入理解类_第43张图片

6.17.5 索引器的get访问器

当使用索引器获取值时,可以通过一个或多个索引参数调用get访问器。索引参数指示获取那个值。

 

get访问器方法体内的代码必须检查索引参数,确定它表示的是那个字段,并返回该字段的值。

get访问器的语法和含义如图6-18所示。图的左边展示了访问器声明的实际语法。右边展示了访问器的语义,把访问器的语义以普通方法的语法写出来。get访问器有如下语义。

  • 它的参数列表和索引器声明中的相同。
  • 它返回与索引器相同类型的值。

6.深入理解类_第44张图片

6.17.6 关于索引器的补充

和属性一样,不能显示的调用get和set访问器。取而代之,当索引器用在表达式中取值时,将自动调用get访问器。当使用赋值语句对索引器赋值时,将自动调用set访问器。

在“调用“索引器时,要在方括号中间提供参数。

6.深入理解类_第45张图片 

6.17.7 为Employee示例声明索引器

下面的代码为先前示例中的类Employee声明了一个索引器。

  •  索引器需要读写string类型的值,所以string必须声明为索引器的类型。它必须声明为poublic 以遍从类的外部访问。
  • 3个字段被强行索引为整数0~2.所以本例中方括号中间名为index的形参必须为int型。
  • 在set访问器放啊体内,代码确定索引指的是那个字段,并把隐式变量value赋值它。在get访问器方法体内,代码确定索引器指的是哪个字段,并返回该字段的值。

6.深入理解类_第46张图片

6.深入理解类_第47张图片 

6.17.8 另一个索引器的实例

下面是一个附加的实例,为类Class1的两个int字段设置索引。

6.深入理解类_第48张图片 

6.深入理解类_第49张图片 

6.17.9 索引器重载

只要索引器的参数列表不同,类就可以有任意多个索引器。索引器类型不同是不够的。这叫做索引器重载,因为所用的索引器都有相同的“名称”:this访问引用。

例如,下面的代码有3个索引器:两个string类型的和一个int类型的。两个string类型的索引中,一个带单独的int参数,另一个带两个int参数。

6.深入理解类_第50张图片

6.18 访问器的访问修饰符

在这一 章中,你已经看到有两种函数成员带get和set访问器:属性和索引器。默认情况下,成员的两个访问器有和成员自身相同的访问级别。也就是说,如果一个属性有public访问级别,那么它的两个访问器都有同样的访问级别,对索引也一样。

不过,你可以认为两个访问器分配不同的访问级别。列如,如下列代码演示了一个非常常见而且重要的例子,那就是为set访问器声明为private,为get访问器声明为public。get之所以是public的是因为属性的访问级别就是public的。

注意,在这段代码中,尽管可以从类的外部读取该属性,但却只能在内部类的内部设置它(本例中是在构造函数内设置)。这是一个非常重要的封装工具。

6.深入理解类_第51张图片

访问器的访问修饰符有几个限制。最重要的限制如下。

  • 仅当成员(属性或索引器)既有get访问器也有set访问器时,其访问器才能有访问修饰符。
  • 虽然两个访问器都必须出现,但它们中只能有一个访问修饰符。
  • 访问器的访问修饰符必须比成员的访问级别有更严格地局限性。

图6-19阐明了访问级别的层次。访问器的访问级别在图标中的位置必须比成员的访问级别位置低。

例如,如果一个访问属性的访问级别是public,在图里较低的4个级别中,可以把任意一个级别给他一个访问器。但如果属性的访问级别是protected,唯一能对访问器使用的访问修饰符private。

6.深入理解类_第52张图片

6.19 分布类和分布类型

类的声明可以分割成几个分部类的声明。

  • 每个分部类的声明都含有一些类型成员的声明。
  • 类的分部类声明可以在同一文件中也可以在不同的文件中。

每个局部变量声明必须被标注为partial class ,而不是单独的关键字class。分布类声明看起来和普通类声明相同,除了那个附加的类型修饰符partial。

6.深入理解类_第53张图片 

例如,图6-20中左边的边框表示一个类声明文件。图右边的框表示相同的类型声明被分割成两个文件。组成类的所有分部类声明必须在一起编译,使用分部类声明的类必须有相同的含义,就好像所有类成员都声明在一个单独的类声明体内。

6.深入理解类_第54张图片 

6.20 分部方法

分部方法是声明在分部类中·不同部分的方法,分部方法的不同部分可以声明在不同的分部类中,也可以声明在同一个类中,分部方法的两个部分如下。

  • 定义分部方法声明。
  1. 给出签名和返回类型
  2. 声明的实现部分只是一个分号
  • 实现分部方法声明
  1. 给出签名和返回类型
  2. 是以正常形式的语句块实现
  • 定义声明和实现声明的签名和返回类型必须匹配。签名和返回类型有如下特征。
  1. 签名不能包括访问修饰符,这使分部方法是隐式私有的。
  2. 参数列表不能包含out参数。
  3. 在定义声明和实现声明中都必须包含上下文关键字partial,直接放在光健字void之前。

6.深入理解类_第55张图片

 6.深入理解类_第56张图片

 

 

 

 

 

 

你可能感兴趣的:(C#,开发语言,c#)