类型设计
7.类型成员及其访问限定
C#中应用于类型、字段、或方法的访问限定修饰符:
Private;public;
Protected:所定义及其派生类型中的方法访问,与所在的程序集无关
Internal: 仅被所定义程序集中的方法访问
Protected Internal: 所定义及其派生类型,以及任何定义在同一程序集中方法访问
C#中如果一个非嵌套类型没有显示标识访问限定修饰符,则默认用Internal来标识
除了访问限定修饰符外,类型和成员还可以用一些预定义特性来标识。
类型的预定义特性:abstract; sealed(不能作为基类)
方法的预定义特性:static; virtual; new; abstract; sealed; override;
8.常数与字段
常数是一个表示恒定不变的值的符号。定义一个常数类型符号时,需在编译时确定它的值,通过编译后,编译器将值保存在所定义的元数据内。
因为只有基元类型的数据成员才能利用文本常数,在编译时直接进行初始化,而非基元类型的数据成员只能在运行时调用构造器来完成初始化,故常数的类型只能是基元类型。
当使用常数符号时,编译器首先从定义常数的模块的元数据中查找出该符号,直接取出常数的值,然后将之嵌入到编译后产生的IL代码中。常数在运行时不再需要任何的内存分配。
字段又称数据成员,它保存着一个值类型的实例、或者一个指向引用类型的引用。
字段是以动态内存的形式存储的,因此只能在运行时获取它们的值。
9.方法
创建一个引用类型的实例:
1.分配内存
2.初始化对象的附加成员
3.调用类型的实例构造器设置对象的初始状态
当构造一个引用类型实例时,在调用其实例构造器之前,系统为该对象分配的内存总是首先被设为0值
默认情况,对于引用类型,编译器会定义一个公有的无参构造器(默认构造器),它允许任何可以访问该类型的代码来构造它的实例。
Class SomeType{
Int32 x=5;
} //SomeType构造器首先将5赋值给了x,紧接着它又调用了基类的构造器(代码膨胀)
class SomeType{
Int32 x=5;
String s=”Hi there”;
public SomeType() {}
public SomeType(Int32 x) {}
} //编译器为以上2个构造器方法产生代码时,每个方法的开始处都将包括初始化x s代码
如果我们有一些需要初始化的实例字段和许多重载的构造器方法,应在定义字段时避免同时对它们进行初始化,相反应将这些公共的初始化语句放在一个初始化构造器中,使其他的构造器显示地调用这个初始化构造器。这将有助于减少生成代码的尺寸。
Class SomeType{
Int32 x;
String s;
Public SomeType() {
X=5;
S=”Hi there”;
}
}
C#编译器不会为值类型自动产生默认的无参构造器;同时,也不允许我们定义无参构造器。
基于性能的考虑,CLR不会尝试为每个包含在引用类型中的值类型字段调用构造器,但会保证值类型中所有的字段都被初始化为0或null
C#编译器不允许值类型有无参构造器,但CLR却允许这样
Struct SomeType{
Int32 x=5;
} //error ; C#不允许值类型有无参构造器
Struct SomeType{
Int32 x,y;
Public SomeValType(Int32 x){
This.x=x;
}
} //error; 为值类型定义的任何构造器都必须要初始化其所有的字段
类型构造器用于设置一个类型的初始状态,默认情况下,一个类型中没有定义类型构造器,若要定义,也只能定义一个,并且,类型构造器不能有任何参数。
class SomeRefType {
static SomeRefType() {}
} //访问限制有C#编译器自动设为私有方式
类型构造器的调用总是由CLR负责,调用时间:
1.类型的第一个实例被创建之前
2.非继承静态字段被第一次访问之前
类型构造器不应调用其基类型的类型构造器,因为基类型中的静态字段并没有被派生类型所继承。(注意:静态成员如方法、属性等,不会被派生类型所继承,它们只是编译时静态绑定)
对CLR来讲,重载操作符仅仅是一些方法而已。
当源类型或目标类型不是基元类型时,编译器将不知道如何执行这样的转换;为了使这样的转换成为可能,Rational类型应该定义一些公有的构造器。
class Rational{
public Rational(Int32 numerator) {…}
public Int32 ToInt32() {…}
public static implicit operator Rational(Int32 numerator){
Return new Rational(value);
}
public static explicit operator Int32(Rational r){
Return r.ToInt32();
}
}
Operator关键字告诉编译器该方法是一个转换操作符,其后,指定对象转型的目标类型,括号内为源类型。Implicit 和explicit的选择根据精度的丢失与否。