1、概念
(1)值类型主要包括简单类型(比如:int,char等)、结构体类型和枚举类型。其实例通常分配在线程的堆栈上,并且不包含任何指向实例数据的指针(变量本身就包含了其实例数据)。
(2)引用类型通常包括类类型、接口类型、数组类型和委托类型等。其实例分配在托管堆上,变量保存了实例数据的内存引用。
2、内存机制
数据在内存中的分配位置,完全取决于该变量的数据类型。
我们知道,在Windows中一个虚拟寻址系统,该系统把程序可用的内存地址映射到硬件内存中的实际地址上。至于怎么映射这完全由windows后台管理,对于32位处理器上的每个进程来说,它都可以使用4GB的内存(无论计算机上有多大的硬件内存空间)。注意:这4GB的内存包含了程序的所有部分(可执行代码、代码加载的所有DLL,以及程序运行时使用的所有变量的内容),我们一般称它为虚拟地址空间。4GB中的每个存储单元都是从0开始往上排序,要访问存储在内存的某个空间中的一个值,就需要提供表示该存储单元的数字。
在进程的虚拟内存中,有一个区域我们称为堆栈。在了解堆栈前,我们需要注意在C#中变量的作用域,如果变量a在变量b之前进入作用域,b就会先出作用域;因此,b的生存期就会包含在a中;在释放变量的时候,其顺序与给它们分配内存的顺序相反。其实变量以什么顺序从内存中删除并不重要,编译器在内部会确保先放在内存中的那个变量后删除。
我们经常会这么想,就是用一个方法来分配内存,来存储一些数据,即使在方法退出很长一段时间后,存储的这些数据我们仍能使用。这就是为什么要使用引用类型,托管堆的作用就可以发挥出来。
托管堆是进程的可用4GB中的另一个内存区域。我们从下面的代码分析中了解托管堆的工作原理
Person person;
person = new Person();
上面代码中:第一步,声明一个Person引用person,在堆栈上给这个引用分配存储空间(注意:这仅是一个引用而不是实际的Person对象),person引用占用了4个字节的空间,包含了存储Person对象的地址。第二步,person = new Person(),先分配托管堆上的内存以存储Person实例(这是一个真正的实例,不知是一个地址);然后把变量person的值设置为分配给新Person对象的内存地址。Person实例并没有放在堆栈中,而是放在内存的托管堆中。
3、嵌套结构
我们经常遇到值类型与引用类型的嵌套,(比如:声明一个类,这个类的私有字段是值类型),它们嵌套时,内存的分配是下面一个规则:
引用类型实例总是分配在托管堆上。
值类型实例总是分配在它声明的地方,声明为局部变量时其被分配在堆栈上,声明为引用类型成员时其被分配到托管堆上。
property 与 attribute 的区别
(1)特性
在MSDN中:公共语言运行时允许添加类似关键字的描述声明,它对程序中的元素进行标注(包括字段、方法、属性和类型等);Attribute和.NET FrameWork文件的元数据保存在一起,可以用来在运行时描述代码,或者在程序运行的时候影响应用程序的行为。其实,定制特性Attribute本质上是一个类,主要为目标元素提供关联附加的信息,并在运行期间以反射的方式来获取附加信息。
(2)属性
属性是面向对象编程的基本概念,提供了对私有字读的访问封装,在C#中以Get和Set访问器方法实现对可读和可写属性的操作,提供了安全和灵活的数据访问。
private、protected、public、internal等修饰符的访问权限
(1)Private
具有最低的访问权限,仅能在类的内部访问。
(2)Protected
只能在该类或派生类中访问,而不管具有继承关系的类是否在同一个程序集中。
(3)Internal
访问仅限于程序集,即同一命名空间可以访问。
(4)Protected Internal
它可以看作是Protected与Internal的并集,意思是:如果是继承关系,无论在不在同一程序集里都能访问;如果不是继承关系,那么只能在同一程序集内访问。
(5)Public
具有最高级别的访问权限,对访问成员没有限制。
接口的本质
根据IL分析可知,IPerson接口本质上仍然被标记为Class,同时提桶了abstract virtual方法GetPerson(右图),因此接口其实本质上可以看作是一个定义了抽象方法的类,该类仅提供了方法的定义。
ADO.NET的五个主要对象
Connection
Connection 对象主要是开启程序和数据源(数据库、EXCEL、XML。。。)之间的连结。没有利用连结对象将数据源打开,是无法从数据源中取得数据。是ADO.NET 的最底层,我们可以自己产生这个对象,或是由其它的对象自动产生。
Command
Command 对象主要可以用来对数据源发出一些指令,例如可以增、删、改、查,以及呼叫存在数据库中的预存程序等。这个对象是架构在Connection 对象上,也就是Command 对象是透过连结到数据源
DataAdapter
DataSetCommand 对象主要是在数据源以及DataSet 之间执行数据传输的工作,它可以透过Command 对象下达命令后,并将取得的数据放入DataSet 对象中。这个对象是架构在Command对象上,并提供了许多配合DataSet 使用的功能。在Beta 2 版中DataSetCommand 对象会更名为DataAdapter。
DataSet
DataSet 这个对象可以视为一个暂存区(Cache),可以把从数据库中所查询到的数据保留起来,甚至可以将整个数据库显示出来。DataSet 的能力不只是可以储存多个Table 而已,还可以透过DataSetCommand 对象取得一些例如主键等的数据表结构,并可以记录数据表间的关联。DataSet 对象可以说是ADO.NET 重量级的对象,这个对象架构在DataSetCommand 对象上,本身不具备和数据源沟通的能力;也就是说我们是将DataSetCommand 对象当做DataSet 对象以及数据源间传输数据的桥梁。
DataReader
当我们只需要循序的读取数据而不需要其它操作时,可以使用DataReader 对象。DataReader对象只是一次一笔向下循序的读取数据源中的数据,而且这些数据是只读的,并不允许作其它的操作。因为DataReader 在读取数据的时候限制了每次只读取一笔,而且只能只读,所以使用起来不但节省资源而且效率很好。使用DataReader 对象除了效率较好之外,因为不用把数据全部传回,故可以降低网络的负载。