热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C#深入理解类型

今日无事,回顾了一下C#基础知识,颇有收获,就自己的理解,写了这篇文章,如有不对,欢迎指正。C#中的类型可以分为两类:值类型与引用类型,如下图所示。值类型通常被分配到线程的堆栈上,

今日无事,回顾了一下C#基础知识,颇有收获,就自己的理解,写了这篇文章,如有不对,欢迎指正。

C#中的类型可以分为两类:值类型与引用类型,如下图所示。

值类型通常被分配到线程的堆栈上,而引用类型则被分配到托管堆上。例如下面例子:

valuetype和reftype在内存中的位置如下所示:

从上面可以看出,值类型与引用类型的区别在于实际数据的存储位置:

值类型的变量和实际数据都存储在堆栈中;而引用类型只有变量存储在堆栈中,变量储存着实际数据的地址,实际数据储存在与地址相对应的托管堆中。

 

但是,上边所说的情况并不是绝对的,也就是说值类型的实例不一定分配到线程堆上。

1、应用类型中嵌套定义值类型

以上代码内存分配情况如下:

如果类的字段类型是值类型,他将作为引用类型实例的一部分,被分配到托管堆中。但那些作为局部变量(例子中的c变量)的值类型,则依然会被分配到托管堆中。

 

2.值类型中嵌套定义引用类型

内存分配如下:

值类型实例总会被分配到它声明的地方,声明的是局部变量时,将分配到栈上,而声明为引用类型成员时,则被分配到托管堆上;而引用类型实例总是被分配到托管堆上。

 

值类型与引用类型除了在内存上分布方面的区别,还有以下几个方面的区别:

1、值类型继承自ValueType,ValueType又继承自System.Object;而引用类型则直接继承自System.Object;

2、值类型不收GC(垃圾回收器)控制,作用域结束时操作系统自行释放,从而减少了托管堆的压力;

3、若值类型是密封的(sealed),你将不能把值类型作为其他任何类型的基类;而引用类型则一般具有继承性,这里指的是类和接口;

4、值类型不能为null,他会默认初始化为数值0;而引用类型默认情况下会初始化为null值,表示不指向托管堆中的任何地址。对值为null的引用类型的任何操作,都会引发NullReferenceExcption异常;

5、由于值类型包含其实际数据,因此在默认情况下,值类型之间的参数传递不会影响变量自身;而引用类型变量保存的是数据的引用地址,他们作为参数被传递时,参数会发生改变,从影响引用类型变量的值。

 

两大类型的转换--装箱和拆箱

隐式转换:由低级别类型向高级别类型转换的过程;

显式转换:也叫强制类型转换;

通过is和as运算符进行安全的类型转换;

通过.NET类库中的Convert类来进行类型转换;

 

装箱拆箱的概念:

装箱:将值类型转换为引用类型的过程;

拆箱:将引用类型转换成值类型的过程;

装箱过程中,系统会在托管堆中生成一份托管堆中值类型对象的副本;而拆箱则是从托管堆中将引用类型所指向的已装箱数据复制回值类型对象的过程。

 

下面介绍装箱与拆箱过程:

1、装箱过程

具体分为以下三个步骤:

(1)内存分配:在托管堆中分配好内存空间以存放复制的实际数据;

(2)完成实际数据的复制:将值类型的实际数据复制到新分配的内存中;

(3)地址返回:将托管堆中的对象地址返回给引用类型变量;

拆箱过程:

(1)检查实例:首先检查要进行拆箱操作的引用类型变量是否为null,如果为null则抛出NullReferenceException异常;如果不为null则继续检查变量是否和拆箱后的类型是同一类型,若结果为否,会导致InvalidCastException异常。

(2)地址返回:返回已装箱变量的实际数据部分的地址;

(3)数据复制:将托管堆中的实际数据复制到栈中;

总结:

由上面图解可以知道,如果程序中有过多的拆箱装箱操作,由于两个过程都需要进行数据复制,该操作会大量额外运行时间,并且在装箱拆箱过程中必须会产生多余的变量,进一步加重了GC的负担,导致程序的性能降低。

参数传递问题剖析:

1、值类型参数的按值传递:

参数分为两类:形参与实参。形参指的是被调用方法中的参数,也就是说方法定义中的参数为形参;实参指的是调用方法时,传递给对应参数的值。

 

对值类型的按值传递,传递的是该值类型实例的一个副本,也就是说形参接受到的是实参的一个副本,被调用方法操作的是实参的一个副本而已;

2、引用类型的按值传递

当传递的参数是引用类型时,传递和操作的目标是指向对象的地址,而传递的实际内容是对地址的复制。由于地址指向的是实参的值,当方法对地址进行操作时,实际上操作了地址所指向的值,所以调用方法后原来实参的值就会被修改。

3string引用类型参数按值传递的特殊情况

虽然string类型为引用类型,然而在按值传递时,传递的实参却不会因为方法中形参的改变而被修改。

string具有不变形,一个string被赋值,则不能再通过代码去修改它的值。上边代码看似oldStr被赋予了新值“New string”,但实际上内存会重新分配一块内存空间来存放“New string”字符串,然后把分配的内存首地址赋给oldStr变量。

4、值类型和引用类型参数的按引用传递

不管是值类型还是引用类型,你都可以使用ref或out关键字来实现参数的按引用传递。并且在按引用传递时,方法的定义和调用都必须显示的调用ref或out关键字,否则会发生编译错误。

在按引用传递时,不参数是值类型还是引用类型,其本质都是一样的,都是通过ref或out关键字来告诉编译器,方法传递的是参数地址而不是参数本身。

 


推荐阅读
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 导出功能protectedvoidbtnExport(objectsender,EventArgse){用来打开下载窗口stringfileName中 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
author-avatar
哀乐交加6
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有