C# - 值类型、引用类型&走出误区,容易错误的说法

时间:2022-02-08 08:31:11

1. 值类型与引用类型小总结

1)对于引用类型的表达式(如一个变量),它的值是一个引用,而非对象。

2)引用就像URL,是允许你访问真实信息的一小片数据。

3)对于值类型的表达式,它的值是实际的数据。

4)有时,值类型比引用类型更有效,有时恰好相反。

5)引用类型的对象总是在堆上,值类型的值既可能在栈上,也可能在堆上,具体取决于上下文。

6)引用类型作为方法参数使用时,参数默认是以‘值传递’方式来传递的,但值本身是一个引用。

7)值类型的值会在需要引用类型的行为时装箱;拆箱则是相反的过程。

2. 误区一 结构是轻量级的类

这个误解存在着多种形式。有人认为值类型不能或不应有方法或有其他意义的行为:它们应作为简单的数据转移类型来使用,只应该有public字段或简单的属性。对于这种说法,一个非常典型的反例就是Datetime类型。DateTime作为值类型来提供是很有道理的,因为它非常适合作为和数字或字符相似的一个基本单位来使用。另外,它也理应被赋予对它的值执行计算的能力。换个角度来看这个问题,是数据转移类型一般都是引用类型。总之,具体应该如何决定,应取决于需要的是值类型的语义,还是引用类型的语义,而不是取决于这个简单类型与否。

还有一些人认为值类型之所以显得比引用类型‘轻’,是因为性能,事实是在某些情况下,值类型很能‘干’:它们不需要垃圾回收,(除非被装箱)不会因类型标识而产生开销,也不需要解引用。但在其他方面,引用类型显得更‘能干’:在传递参数、赋值、将值返回和执行类似的操作时,只需复制4或8字节(需要看运行的是32位或是64位CLR),而不是复制全部数据。假定ArrayList是一个所谓‘纯的’值类型,那么将一个ArrayList表达式传给一个方法时,就得复制它的所有数据!几乎在所有情况下,性能问题都不是根据这种判断来决定的。瓶颈从来都不是想当然的,在你根据性能进行设计之前,需要衡量不同的选择。

值得注意的是,将这两者相结合也不能解决问题:类型(不管是类还是结构)拥有多少方法并不重要,每个实例所占用的内存不会受到影响。(代码本身会消耗内存,但这只会发生一次,而不是每个实例都发生)

3. 误区二 引用类型保存在堆上,值类型保存在栈上

这个误区主要应归咎于转述这句话的人根本没有动脑筋。这一部分是正确的,引用类型的实例总是在堆上创建的。但第二部分就有问题了。

前面讲述过,变量的值是在它声明的位置存储的。所以,假定一个类中又一个int类型的实例变量,那么在这个类中的任何对象中,该变量的值总是和对象中的其他数据在一次,也就是在堆上。只有局部变量(方法内部声明的变量)和方法参数在栈上。对于C#2或以上版本,很多局部变量并不完全存放在栈中。

4. 误区三 对象在C#中默认是通过引用传递的

这或许是传播得最广的一个误区了。统一说这句话的人一般知道C#实际的行为是什么,但不知道‘引用传递pass by reference’的真正意思是什么。可惜,那些真正知道引用传递是什么意思的人,在听到这句话时会被完全搞糊涂。

‘引用传递’的正式定义相当复杂,要涉及坐值(1-values)和类似的计算机科学术语。但最重要的一点是,假如以引用传递的方式来传送一个变量,那么调用的方法可以通过更改其参数值,来改变调用者的变量值。现在请记住,引用类型变量的值是引用,而不是对象本身。不需要按引用来传递参数本身,就可以更改该参数的引用的那个对象的内容。例如,下面的方法更改了相关对象StringBuilder的内容,但调用者的表达式引用的仍然是之前的那个对象:

        public void AppendHello(StringBuilder builder)
{
builder.Append("Hello");
}

调用这个方法时,参数值(对StringBuilder的一个引用)是以值传递pass by value 的方式传递的。如果想在方法内部更改builder变量的值,如执行builder=null 语句,调用者看不见这个改变,刚好跟错误认识相反。

有趣的是,这种错误说法中,不仅引用传递的说法有误,而且 对象传递的说法也存在问题。无论引用传递还是值传递,永远不会传递对象本身。涉及一个引用类型时,要么以引用传递的方式传递变量,要么以传值的方式传递参数值(引用)。最起码,这回答了‘当null作为一个传值参数的值来使用时会发生什么’的问题。假如传递的是对象,这是就会出问题,因为没有一个对象可供传递!相反,null引用会采用和其他引用一样的值传递方式传递。

可以关注本人的公众号,多年经验的原创文章共享给大家。

C# - 值类型、引用类型&走出误区,容易错误的说法

C# - 值类型、引用类型&走出误区,容易错误的说法的更多相关文章

  1. 数往知来C#之接口 值类型与引用类型 静态非静态 异常处理 GC垃圾回收 值类型引用类型内存分配<四>

    C# 基础接口篇 一.多态复习 使用个new来实现,使用virtual与override    -->new隐藏父类方法 根据当前类型,电泳对应的方法(成员)    -->override ...

  2. 30天C#基础巩固-----值类型/引用类型,泛型,空合并操作符(??),匿名方法

    一:值类型/引用类型的区别      值类型主要包括简单类型,枚举类型,和结构体类型等,值类型的实例通常被分配在线程堆栈上面变量保存的内容是实例数据本身.引用类型被分配在托管堆上,变量保存的是地址.引 ...

  3. 深入C#内存管理来分析值类型&引用类型,装箱&拆箱,堆栈几个概念组合之间的区别

    C#初学者经常被问的几道辨析题,值类型与引用类型,装箱与拆箱,堆栈,这几个概念组合之间区别,看完此篇应该可以解惑. 俗话说,用思想编程的是文艺程序猿,用经验编程的是普通程序猿,用复制粘贴编程的是2B程 ...

  4. C# 值类型 引用类型

    CLR 定义了两种类型,ReferenceTypes引用类型 和 ValueTypes 值类型.我们定义的各种Class都是引用类型,而我们用的decimal int 之类是值类型. 他们有什么区别呢 ...

  5. (值类型引用类型)和null的关系

    1.null    null表示变量没有指向任何对象. 2.值类型    包括 bool.结构体.枚举.int.double.float等等 .在.NET中值类型都继承自ValueType. 3. 引 ...

  6. JAVASCRIPT数据类型(值类型-引用类型-类型总览)

    值类型:也称为原始数据或原始值(primitive value). 这类值存储在栈(stack)中,栈是内存中一种特殊的数据结构,也称为线性表,栈按照后进先出的原则存储数据,先进入的数据被压入栈底,最 ...

  7. 深入理解C#学习笔记之走出误区

    通过学习深入理解C#这本书,发现自己对于C#这门语言一直存在着三个误区. 第一个误区:结构是轻量级的类: 我一直认为值类型不应该具有方法或其他有意义的行为,它们只应该具有一些简单的属性.但书中总结了一 ...

  8. js的基础(平民理解的执行上下文/调用堆栈/内存栈/值类型/引用类型)

    与以前的切图比较,现在的前端开发对js的要求似乎越来越高,在开发中,我们不仅仅是要知道如何运用现有的框架(react/vue/ng), 而且我们对一些基础的知识的依赖越来越大. 现在我们就用平民的方法 ...

  9. c#值类型引用类型第一章

    概要 本篇文章主要简单扼要的讲述值类型和引用类型更进阶的理解和使用.如果希望更多的了解和技术讨论请记得看文章末尾,望各位看官多多支持多多关注,关注和支持是我更新文章的最大动力.在这里谢谢大家.温馨提示 ...

随机推荐

  1. 【URAL 1917】Titan Ruins: Deadly Accuracy(DP)

    题目 #include<cstdio> #include<algorithm> using namespace std; #define N 1005 int n, m, cn ...

  2. os

    内核,Shell和文件结构一起形成了基本的操作系统结构. from:大学生攻克Linux系统教程(又名天下没有难学的Linux) 发问: 0-内核,再怎么分出层次呢?

  3. cocos2dx与Lua以及quick cocos

    1.cocos2dx中的脚本架构与组件 2.quick cocos的开发优势 3.自定义c++类如何导出到lua

  4. or1200下raw-os&lpar;仿真环境篇&rpar;

    貌似最近都在公司混日子过了,怎么办?哎哎哎~罪过啊罪过,不过也是的,加工资居然没我份,顶领导个肺的,叫我怎么继续活啊~哎哎哎~ 算了,不谈这些鸟事情了,说多了都是泪啊,这篇blog开始我们进入raw- ...

  5. Graph Search图谱搜索

    来自百度百科的解释: Graph Search为2013年1月16日,Facebook首席执行官马克·扎克伯格(Mark Zuckerberg)在门罗帕克公司总部召开的新闻发布会上宣布推出社交搜索工具 ...

  6. Windows Phone 8初学者开发—第13部分:设置LongListSelector中磁贴的样式

    原文 Windows Phone 8初学者开发—第13部分:设置LongListSelector中磁贴的样式 第13部分:设置LongListSelector中磁贴的样式 原文地址: http://c ...

  7. Ubuntu Firefox HTML5

    sudo apt-get install ubuntu-restricted-extras

  8. javaweb&lpar;1&rpar;之tomcat使用

    安装 1.点击下载. 2.解压到一个目录. 3.进入解压后的 bin 目录,双击该文件夹下的 startup.bat 即可运行. 4.若运行成功,会有一个窗口悬停如下: 访问地址: localhost ...

  9. QT QListWidget 简单的操作

    以下是简单的 listWidget 的方法的功能 listWidget = QListWidget() #实例化一个(item base)的列表 listWidget.addItem('dd') #添 ...

  10. &lbrack;CodeForces332E&rsqb;Binary Key

    Problem 题目给出一个加密前的字符串长度为p和加密后的字符串长度为s,让你求一个长度为K字典序最小的密钥. 密钥是循环的,第i位为1表示加密前的第i为是有用的否则是没用的. Solution 首 ...