zoukankan      html  css  js  c++  java
  • CLR via C#-类型基础

    一、所有类型都从System.Object派生

    运行时要求每个类型最终都从System.Object类型派生,也就是说,以下两个类型定义完全一样

    //隐式派生自System.Object
    class Employee{}
    //显式派生自Object
    class Employee:System.Object{}

    System.Object类提供了如下所示的公共实例方法,所以每个类型的每个对象都保证了一组最基本的方法。

    Equals()//如果两个对象有相同的值,返回true​
    GetHashCode()//返回对象值的哈希码
    ToString()//返回类型的完整名称
    GetType()//返回从Type派生的一个类型的实例,指出调用该方法的对象是什么类型

    二、实例化对象时new操作符所做的事情

    计算类型及其所有基类型中定义的所有实例字段需要的字节数。堆上每个对象都需要一些额外的成员,包括类型对象指针和同步块索引。CLR利用这些成员管理对象,额外成员的字节数要计入对象大小。

    从托管堆中分配类型要求的字节数,从而分配对象的内存,分配的所有字节都设为0。

    初始化对象的类型对象指针和同步块索引成员。

    ④调用类型的实例构造器,传递在new调用中指定的实参。大多数编译器都在构造器中自动生成代码来调用基类构造器。

    Employee e=new Employee("ConstructorParam1");

    new执行了所有这些操作后,返回指向新建对象一个引用或指针。

    如上示例代码中,该引用保存到变量e中,后者具有Employee类型。

    实例对象内存的释放

    C#没有和new操作符对应的delete操作符,没有办法显式释放为对象分配的内存。

    不过CLR采用了垃圾自动回收机制,能自动检测到一个对象不再被使用或访问并自动释放对象的内存。


    三、类型转换

    类型安全性

    CLR最重要的特性之一就是类型安全,调用GetType方法获取对象的确切类型。

    由于GetType方法是虚方法,所以一个类型不可能伪装成另一个类型。

    例如Employee类型不能重写GetType方法返回一个SuperHero类型。

    向基类型转换:隐式转换

    C#不要求任何特殊语法即可将对象转换为他的任何基类型,向基类型的转换被认为是一种安全的隐式转换。

    向派生类转换:显式转换

    将对象转换为他的某个派生类型时,C#只能显式转换,因为这种转换可能在运行时失败

    //该类型隐式派生自System.Object
    internal class Employee{}
    //测试类
    Object o=new Employee();//不需要转型,new返回一个Employee对象,而Object是Employee的基类型
    Employee e=(Employee)o;//需要转型,Employee派生自Object

    在运行时,CLR检查转型操作,确定总是转换为对象的实际类型或者他的任何基类型。

    使用C#的is操作符进行转型

    is检查对象是否兼容于指定类型。返回Boolean值true或false,is操作符永不抛出异常。

    例如以下代码:

    Object o=new Object();
    Boolean b1=(o is Object);//b1为true
    Boolean b2=(o is Employee);//b2为false

    如果对象引用null,is操作符总是返回false,因为没有可检查其类型的对象。

    is操作符通常这样使用:

    if(o is Employee){
      Employee e=(Employee)o;
    }

    在上述代码中,CLR实际检查两次对象类型,is操作符首先核实o是否兼容与Employee类型。

    如果是,在if语句内转型,CLR再次核实o是否引用一个Employee。

    使用C#的as操作符进行转型

    CLR的类型检查增强了安全性,但无疑会对性能造成一定影响,这是因为CLR首先必须判断变量的引用的对象的实际类型。

    CLR必须遍历继承层结构,用每个基类型去核对指定的类型。

    由于这是一个常用的编程模式,C#专门提供了as操作符,简化这种代码的写法并提升性能。

    Employee e=o as Employee;
    if(e!=null){
        //在if语句中使用e
    }

    在上述代码中,CLR核实o是否兼容于Employee类型。如果是,as返回对同一个对象的非null引用,如果不兼容,返回null。

    as操作符使CLR只校验一次对象类型,if语句只检查e是否为null,速度比校验对象的类型快得多。

    as操作符的工作方式与强制类型转换一样,只是它永不抛出异常,如果对象不能转型,结果就是null,企图直接使用最终生成的引用会抛出System.NullReferenceException异常。

    以下代码对此进行了演示:

    Object o = new Object();//新建Object对象
    Employee e=o as Employee;//将o转型为Employee
    //上述转型会失败,不抛出异常,但e被设为null
    e.ToString();//访问e抛出NullReferenceException异常

    四、命名空间和程序集

    使用using指令简化命名空间

    C#编译器通过using指令提供这个机制,例如:

    using System.IO;
    using System.Text;

    只需要在代码中输入FileStream和StringBuilder这两个简化的类型名称,编译器就会自动将引用展开成System.IO.FileStream和System.Text.StringBuilder。

    使用using指令创建别名

    可能两个或更多类型在不同命名空间中同名。比如使用如下所示代码的引用,二者都有Wifget的类型。

    微软强烈建议为类型定义具有唯一性的名称。为了消除歧义,必须显式告诉编译器创建哪个的。

    using Microsoft;//尝试附加"Microsoft."前缀
    using Wintellect;//尝试附加"Wintellect."前缀

    而using指令的另一种形式允许为类型或命名空间创建别名,以消除不同命名空间的重名的类的歧义。

    //将WinerllectWidget 符号定义成Wintellect.Widget的别名
    using WinerllectWidget = Wintellect.Widget

    外部别名

    C#还提供了外部别名(extern alias)的功能,来解决命名空间和类型都重名的情况。

    外部别名还允许从同一程序集的两个不同版本中访问一个类型

    命名空间和程序集的关系

    命名空间和程序集(实现类型的文件)不一定相关,特别是,同一个命名空间中的类型不可能在不同程序集中实现。同一个程序集也可能包含不同命名空间的类型。

  • 相关阅读:
    php_memcache扩展
    window+nginx+php
    服务启动Apache服务,错误Parent: child process exited with status 3 -- Aborting.解决
    PHP文件下载
    gvim
    单车家族 结对项目三
    单车家族 结对项目二
    共享单车 网络定位
    注册页面 android 仿摩拜单车共享单车进度条实现StepView
    结对项目 ——功能结构图
  • 原文地址:https://www.cnblogs.com/errornull/p/9741276.html
Copyright © 2011-2022 走看看