CLR - 设计类型

前言


  好记性不如料“笔头”系列。。。

  类型基础

  基元类型、引用类型和值类型

类型基础

“运行时”要求每个类型最终都从System.Object 类型派生。

  由于所有类型最终都从System.Object 派生,所以可以保证每个类型的每个对象都有一组最基本的方法。具体地说,System.Object
类型提供了下列的公共实例方法:


















公共方法名称 说明
Equals 如果两个对象具有相同的值,就返回true。
GetHashCode 返回对象的值的一个哈希码。
ToString

该方法默认返回类型的完整名称(this.GetType().FullName)。然而,我们经常需要重写这个方法,使它返回一个String
对象,其中包含对象状态的一个表示。例如,核心类型(比如Boolean
和Int32)重写了这个方法,返回它们的值的一个字符串表示。

GetType 返回从Type 派生的一个对象的实例,指出调用GetType
的那个对象是什么类型。返回的Type 对象可以和反射类配合使用,从而获取与对象的类型有关的元数据信息。

  此外,从System.Object 派生的类型能访问下列所示的受保护方法:












受保护的方法名称 说明
MemberwiseClone 这个非虚方法能创建类型的一个新实例,并将新对象的实例字段设与this
对象的实例字段完全一致。返回的是对照新实例的一个引用。
Finalize 在垃圾回收器判断对象应该被作为垃圾收集之后,在对象的内存被实际回收之前,会调用这个虚方法。需要在回收之前执行一些清理工作的类型应该重写这个方法。

  要求所有对象都用new 操作符来创建。下面这行代码展示了如何创建一个class1 对象:

  Program p = new Program("info");

  以下是new 操作符所做的事情。

  1:计算类型及其所有基类型(一直至System.Object)中定义的所有实例字段需要的字节数。堆上的每个对象都需要一些额外的成员——即”类型对象指针“(type
object pointer)和“同步块索引”(sync block index)来由CLR 用于管理对象,这些额外成员的字节数会计入对象大小。

  2:从托管堆中分配指定类型要求的字节数,从而分配对象的内存,分配的所有字节都设置为零(0)。

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

  4:调用类型的实例构造器,向其传入在对new
的调用中指定的任何实参(上例就是字符串"info")。大多数编译器都在构造器中自动生成代码来调用一个基类构造器。每个类型的构造器在调用时,都要负责初始化由这个类型定义的实例字段。最终调用的是System.Object
的构造器,该构造器只是简单地返回,不会做其他任何事情。

CLR 允许将一个对象转换为它的(实际)类型或者它的任何基类型。

  在C# 中进行类型转换可以使用is 与as 操作符。

  is 操作符检查一个对象是否兼容于指定的类型,并返回一个Boolean 类型:true 或false。注意,is 操作符永远不会抛出异常。

  Object o = new Object();

  Boolean b1 = (o is Object); //返回true

  as 操作符检查一个对象是否兼容于指定的类型,如果兼容,as 会返回对同一个对象的一个非null 引用,反之,则返回null。

  Object o = new Object();

  string str= o as string;//返回null

类型、对象、线程栈、托管堆在运行时的相互联系

  运行程序时,会启动一个进程,每个进程最少有一个线程。一个线程被创建时会分配到1MB
大小的栈。这个栈的空间用于向方法传递实参,并用于方法内部定义的变量。

  现在,Windows 进程已经启动,CLR 已经加载到其中,托管堆已初始化,而且已创建一个线程(连同它的 1MB 栈空间)。现在已经进入 Main()
方法,马上就要执行 Main 中的语句,所以栈和堆的状态如下图所示:

  当JIT 编译器将Main() 方法的IL代码转换成本地CPU 指令时,会注意到其内部引用的类型。这个时候,CLR
要确保定义了这些类型的所有程序集都已加载。然后利用程序集的元数据,CLR
提取与这些类型有关的信息,并创建一些数据结构来表示类型本身。在线程,会创建所需要的所有对象。下图显示了在Main 被调用时,创建类型对象后的状态:

  当CLR 确定方法需要的所有类型对象都已创建,而且Main 方法的代码编译之后,就允许线程开始执行Main 的本地代码。Main
的“序幕”代码执行时,必须在线程栈中为局部变量分配内存。同时作为“序幕”代码的一部分,CLR 会自动将所有变量初始化为null 或0(零)。

  然后Main 执行它的代码来构造一个Person 对象。这造成在托管堆中创建Person 类型的一个实例(也就是一个Person
对象),同时包含类型及其所有基类型(一直至System.Object)中定义的所有实例字段与同步块索引、类型对象指针。CLR
会自动先初始化同步块索引,并将对象的所有实例字段设为null 或0(零),再调用类型的构造器,最后返回Person 对象的内存地址,该地址保存在变量p
中。

  下一步Main 执行到ToString 方法。Jit 编译器在Person 类型对象的方法表中查找引用了被调用方法的记录项,对方法进行JIT
编译(如果还没有编译过),再调用JIT 编译的代码。

  这时。可以看到Person 类型对象中也包括类型对象指针,这是因为类型对象本质上也是对象。CLR 创建类型对象时,必须初始化这些成员。CLR
开始在一个进程中运行时,会立即为MSCorLib.dll 中定义的System.Type 类型创建一个特殊的类型对象。Person
类型对象都是System.Type 类型对象的一个“实例”。因此,Person
类型对象指针成员会初始化成对System.Type类型对象的引用。因System.Type
类型对象本身也是一个对象,内部的“类型对象指针”成员会指向它本身。

CLR - 设计类型,布布扣,bubuko.com

时间: 2024-10-24 05:03:32

CLR - 设计类型的相关文章

CLR设计类型之接口(一)

写到这一节的时候,CLR设计类型就已经结束了,因为CLR要求的是有一定基础的人看的,所以我们不是从基础类型以及运算符开始的,文章从一开始就讲的是深入面向对象编程,研究C#程序的设计模式.C#面向对象编程有三个特点:封装,继承,多态.接口的实现就是实现继承 其实在开始之前说一下这两天发生的事情,前几天维护项目代码时,虽然是自己写得但是由于逻辑判断比较多,有些变量名起的也不是很有意义,在看的时候就完全忘记当初为啥要写成这样了,也是有点汗颜,所以最近就把代码整洁之道也放在了看书的目录上,今后的示例代码

第二部分 设计类型:第10章 属性

第二部分 设计类型:第10章 属性

CLR值类型和引用类型

知识点:引用类型.值类型.装箱.拆箱 CLR支持两种类型:引用类型和值类型.引用类型在堆上分配内存,值类型在线程栈上分配内存.值类型与引用类型如下所示: 值类型对象有两种表示形式:未装箱和已装箱.将一个值类型的变量付给另一个值类型变量,会执行一次逐字段的复制. 装箱:将一个值类型转换为一个引用类型称为装箱.装箱会发生如下操作: 1.在托管堆中分配好内存.分配的内存大小等于值类型各个字段需要的内存大小之和加上类型对象指针和同步块索引需要的内存量. 2.值类型的字段复制到新分配的堆内存. 3.返回对

Oracle数据库设计类型选择错误的隐患

数据类型不准确的一个隐患,下面来构造一张表存日期字段,一个存varchar2,一个存date,做一个测试.之前也写过两篇blog: 1.字段类型设计与实际业务不符引发的问题1 2.字段类型设计与实际业务不符引发的问题2 SQL> drop table test purge; SQL> create table test as select to_char(to_date('2014-01-01','yyyy-MM-dd')+rownum,'yyyymmdd') s_date, to_date(

mysql_数据库设计类型选择及优化

数据库设计原则: a,更小的通常更好. 应该尽量使用可以正确存储数据的最小数据类型.如只要存储0-200,tinyint unsigned更好 b,简单就好 简单的数据类型的操作需要更少的cpu周期.同时后期优化也更为容易. c,尽量避免使用null mysql在建立索引,优化过程对null需要做特殊处理,耗费额外资源.非特殊情况,避免使用null. 数据类型常识 一,整数类型 根据存储空间: TINYINT SMALLINT MEDIUMINT INT BIGINT 存储空间位数n 8 16

前端常见布局设计类型

Static 静态布局 Liquid 流式布局 Adaptive 自适应布局 Responsive 响应式布局 示例网站:点击查看 原文地址:https://www.cnblogs.com/xingyadian/p/8453064.html

由浅入深学习.NET CLR 系列:目录

经过对Android的一阵折腾,些许熟悉了一些Java的东东,又开始转战.NET.我觉得学习最好和工作不要相离太远,才会更加随笔随意,索性整理一些比较系统的.NET的基础知识学习学习.一提起学习.NET,最经典莫过于CLR via C#了,既然奉为经典,那就从这里开始吧.据此初步整理出如下目录来: 由浅入深学习.NET CLR 基础系列 CLR 的执行模型 生成.打包.部署和管理应用程序及类型 共享程序集和强命名程序集 由浅入深学习.NET CLR 设计类型 类型基础 基元类型.引用类型和值类型

CLR via C#深解笔记二 - 类型设计

类型基础 所有类型都从System.Object派生 CLR要求所有对象都用new 操作符来创建. Employee e = new Employee("Constructor Parameters"); 以下是 new 操作符所做的事情: #1, 计算类型及所有基类型(一直到System.Object, 虽然它没有定义自己的实例字段)中定义的所有实例字段需要的字节数. 堆上的每个对象还需要一些额外(overhead 开销成员)的成员 -- 即“类型对象指针”(type object

NET CLR via C#(第4版)第4章 类型基础

本章内容: 1 所有类型都从System.Object派生 2 类型转换 3 命名空间和程序集 4 运行时的相互关系 本章讲述使用类型和CLR时需掌握的基础知识.具体地说,要讨论所有类型都具有的一组基本行为. 讨论类型安全性.命名空间.程序集.以及如何将对象从一种类型转换成另一种类型. 本章最后会解释类型.对象.线程栈和托管堆在运行时的相互关系. 4.1 所有类型都从System.Object派生 CLR要求每个类型最终都从System.Object类型派生.从而确保类每个对象都具备一组最基本的