访问控制符
C#中的访问控制符有5个,其中基本的有4个:public
,protected
,private
,internal
,还有1个复合的修饰符protected internal
(也可以写成internal protected
)。
类的成员的可访问性有两个方面的含义:一种是基于逻辑的,例如protected表示其子类也可以访问;一种是基于物理的,即可访问性跟是否在同一程序集(assembly)中有关,如internal表明在同一程序集类可访问。
- 程序集,也称“程序装配”,是指编译时将多个类(编译后的MSIL指令)放入到同一个文件中(一般是.dll文件或.exe文件)。
类成员的修饰词与可访问性的关系如下表所示:
各种元素能使用的访问控制符如下表所示:
static修饰符
简单的说,static就是“非实例的”。
可以修饰字段,方法等。
static构造方法
用static修饰的构造方法,即静态构造方法,也称“静态构造函数”。静态构造方法不能有参数,不能有其他修饰符。一个类最多只能有一个静态构造方法。
类的静态构造方法与类的实例构造方法的区别:
- 实例构造方法对每个新创建的对象初始化,静态构造方法则对类自身进行初始化。
- 实例构造方法是在用new运算符产生新对象时由系统自动执行的;而静态构造方法一般不能由程序来调用,它在所属的类加载入内存时由系统调用执行。系统总能保证静态构造方法在所有的静态成员之前执行,也能保证在任何一个实例被创建之前执行。
- 同static方法一样,它不能访问实例字段和实例方法。
static类及using static类
- C# 2.0以上版本,类也可以用
static
修饰,表明该类的所用成员都死static。例如System.Console
类,System.Math
类。 - C# 6.0以上版本,可以导入static类,从而可以省略类名而直接写方法名。例如:前面写
using static System.Console
; 后面可以直接写WriteLine() 它相当于Console.WriteLine()。
const及readonly
1. const修饰的类成员
类的成员若被const修饰,则被称为“常量(constant)”。常量的声明方法如下:
修饰符 const 类型 常量名 = 常量表达式;
常量与字段都是成员,但常量有一些重要得特点:
- 必须在定义时赋值,且不能用变量赋值。
- 不能对常量进行修改。
- 常量的类型可以为简单类型、枚举类型、各种引用类型。这里的引用类型,如果不是
string
,则只能赋以null
。常量的类型不能为简单的struct类型。如果要实现struct
类型的保持不变的量,可以用readonly
。 const
常量隐含static
修饰符,只能通过类名来访问。
const
不仅可以修饰类成员,还可以修饰局部变量。
readonly字段
与const
相比,readonly
有以下特点:
- readonly字段可以是各种类型(而const只可以是简单类型及字符串)。
- readonly字段可以用变量或表达式进行赋值。
- readonly不能修饰局部变量。
- readonly字段并不隐含static性质。
- readonly字段不要求定义时初始化。赋值时也可以在构造方法中赋值,包括out及ref参数进行处理。但最多只能赋值一次。
可以看出readonly
要求的只读性是考虑“运行时是只读的”,而const
要求的只读性是“编译时就是常量”。
事实上,readonly
用于程序中,还常常与static
一起使用,来实现类似“常量”的功能。例如用readonly static
字段来表示“常量”的颜色。
public class Color
{
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
public Color(byte r, byte g, byte b){
red = r;
green = g;
blue = b;
}
}
sealed及abstract
sealed类
sealed(密封)可用于对类的修饰。如果一个类被sealed
所修饰定义,说明这个类不能被继承。
abstract类
abstract(抽象)可以修饰类及类的一些成员(方法、属性、索引器)。
抽象类就是没有具体对象的概念类。抽象类不能被实例化,为了创建对象,这样的类必须被继承,然后创建及子类的对象实例。
定义抽象类的意义在于:抽象类是其所有子类的公共属性的集合,所以使用抽象类的一大优点就是可以充分利用这些公共属性来提高开发和维护的效率。C#中的System.Array
类就是一个抽象类,它表示了所有数组的公共父类。
定义一个抽象类的格式如下:
abstract class 类名
{
...
}
注意: 虽然抽象类不能实例化,但是抽象类可以有构造函数,这些构造函数可以被子类的构造函数所调用。
abstract方法、属性、索引器
被abstract所修饰的方法称为抽象方法,抽象方法的作用在于它的所有子类定义一个统一的接口。对抽象方法只需声明,而不需实现,格式如下:
abstract 类型 方法名(参数列表);
抽象属性的定义格式如下:
abstract 类型 属性名
{
get; set;
}
抽象索引器的定义格式如下:
abstract 类型 this [参数列表]
{
get; set;
}
使用abstract
时要注意以下几点:
- abstract不能与static并列修饰同一方法。
- abstract不能与private并列修饰同一方法,也不能省略访问控制符。
- abstract方法必须位于abstract类中。
- 子类在实现一个abstract方法时,要用override修饰,否则不认为是实现了该抽象方法,而认为是一个新(new)的方法。
new、virtual、override
1. new
前面有写到的new
成员的隐藏等等…
2. virtual及override
virtual
可以修饰方法、属性和索引器。用virtual
修饰的成员称为虚成员。一个虚成员在子类中,可以被覆盖(override)。
使用virtual
及override
时的注意事项:
- virtual及override不能与static并列修饰同一方法。
- virtual及override不能与private并列修饰同一方法,也不能缺省访问控制符。
- abstract成员隐含是virtual的,但abstract不能与virtual并列修饰同一成员。
- 子类在实现一个abstract或virtual方法时,要用override修饰,否则不认为是实现了该抽象方法,而是一个新(new)的方法。
- 一个override成员可以在其子类中进一步覆盖。
- 一个override的成员一定在其直接父类或间接父类有对应的virtual、abstract或override成员。
3. sealed override
在子类中为了防止进一步对父类的虚方法进行覆盖,可以使用sealed
方法(封闭方法)。sealed
这时必须与override
一起使用。
例如:
class A
{
public virtual void M(){...}
}
class B : A
{
public sealed override void M(){...}
}