Richie

Sometimes at night when I look up at the stars, and see the whole sky just laid out there, don't you think I ain't remembering it all. I still got dreams like anybody else, and ever so often, I am thinking about how things might of been. And then, all of a sudden, I'm forty, fifty, sixty years old, you know?

CLR/C# 的一些语言特性

    1. new和override区别
    override在子类中重写基类的方法;new在子类中为基类同名(virtual)方法添加一个新的版本,会保留基类的同名(virtual)方法。
    如果基类的同名方法不给出new和override修饰符,.Net默认采用new的方式,编译时将产生一条警告信息。
    关于重载:一般有按名称隐藏和按签名隐藏两种策略,C#默认按签名隐藏,即默认使用hidebysig特性。

    2. 构造函数
    a) static构造函数.cctor,对类型初始化。在类里面声明的静态变量将由C#编译器自动编译到.cctor中,如果有显示的声明静态构造器,也是编译到.cctor(在.cctor中局部静态变量将位于显示声明的静态构造器前面)。
    CLR有两种策略决定.cctor的执行时间,第一种是首次使用类型时,第二种是首次使用类型的静态成员时通过给类型添加beforefieldinit 元数据特性)。C#编译器对没有显示声明静态构造器的类型默认设置beforefieldinit特性,对存在显示静态构造器的类型不会设置。
    b) 类的构造函数.ctor。要注意的一点是CLR分配对象时将调用深度派生(most-derived)类型的构造函数方法,在派生类型构造函数的最开始位置调用基类构造方法,不管在派生类型本身还是基类的构造函数中,对象的实际类型都是派生类型。在这样的机制下,有些问题需要谨慎处理,例如如果基类在构造函数中调用被override过的virtual方法,而这时派生类的构造函数并没有执行。

    3. abstract, virtual
    abstract的类不能实例化,只能用于子类继承。
    abstract的方法隐式的就是一个virtual方法;abstract的方法子类必须实现;abstract方法只能有声明,不能包含实现。
    virtual方法提供给子类override;可以包含实现。

    4. as和强制类型转换
    强制类型转换:MyClass myclass=(MyClass)obj; 使用as:MyClass myclass=obj as MyClass;
    区别在于,如果obj不能被转换成MyClass类型,强制类型转换会抛出异常,而使用as时不会有异常,只是转换结果(myclass变量)的值为null。
    强制类型转换使用castclass操作码(opcode)实现,as转换、is判断使用isinst操作码实现。这两个操作码都使用类型的元数据信息,将对象转换成给定类型放在当前计算堆栈上,只不过无法转换时一个抛异常,另一个将null放在堆栈中。
    关于类型转换:每个对象通过header中的类型句柄引用类型元数据,在类型元数据中有一个interface table,指示类型实现了哪些接口(每个项都包含指向接口元数据的类型指针),一个基类类型元数据指针,在接口、继承体系之间的类型兼容性测试主要基于这些信息进行。类型转换另外需要考虑的,是类型是否有重载隐式、显示类型转换操作等。

    5. 修饰符
    private,只能在同一个类中调用。
    protected,可在派生类中调用,无论派生类型是否在同一个assembly中。
    internal,只能在同一个assembly中调用。
    protected internal,可以在任何assembly的派生类型中调用,也可由同一个assembly中的任何类型调用。

    6. readonly / const区别
    const在编译之后将常量编译到指令流中,只在元数据保留有常量名和值的信息。readonly的变量只能在声明时提供初始化值,或者在构造函数中初始化,之后变量的值不再允许修改。

    7. ref和out区别
    都是表示引用方式传递参数,out明确要求调用者进行初始化,ref对调用方和被调用方都没有明确的职责要求。因此对于out型的参数,如果在调用之前没有初始化赋值,会产生一个编译器错误。

posted on 2007-04-01 22:24  riccc  阅读(688)  评论(2编辑  收藏  举报

导航