前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >C#篇(三)——函数传参之引用类型和值类型

C#篇(三)——函数传参之引用类型和值类型

作者头像
yaphetsfang
发布于 2020-07-30 02:01:03
发布于 2020-07-30 02:01:03
96500
代码可运行
举报
文章被收录于专栏:yaphetsfangyaphetsfang
运行总次数:0
代码可运行

首先应该认清楚在C#中只有两种类型:

1、引用类型(任何称为“类”的类型) 2、值类型(结构或枚举)

先来认识一下引用类型和值类型的区别:

函数传参之引用类型:

1、先来一个简单的引用类型传参的实例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//使用了C#6.0的一个新特性:using static System.Console;
    class Program
    {
        static void StartTest1(string test)
        {
            test = "test2";
            WriteLine(test);//输出:"test2"
        }

        static void StartTest2(string test)
        {
            test = null;
            WriteLine(test);//输出:(空白)
        }

        static void Main(string[] args)
        {
            string test = "test1";
            WriteLine(test);//输出:"test1"

            StartTest1(test);
            WriteLine(test);//输出:"test1"

            StartTest2(test);
            WriteLine(test);//输出:"test1"
        }
    }

输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
test1
test2
test1

test1

结果分析:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
首先明白字符串(string)类型是引用类型,但改变了它的值之后,并没有影响到函数外面那个实参的值,这可能与大家的常识有点相违背,因为我们都知道若是变量以"引用传递"的方式传递,那么调用的方法可以通过更改其参数值,来改变调用者的变量值,但这里有一点需要说明的是:"引用传递"不是等价于引用类型传参,这是很多人的误解的地方。其实在C#当中,引用类型和值类型默认都是以“传值”的方式传递数值(引用)的(引用类型的值就是引用(类似索引或地址),而不是对象本身)。
请看下图详细分析:

2、再来一个略微复杂的引用类型传参的实例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    class Program
    {
        static void StartTest1(StringBuilder test)
        {
            test.Append("test2");
            WriteLine(test);//输出:"test1test2"
        }

        static void StartTest2(StringBuilder test)
        {
            test = null;
            WriteLine(test);//输出:(空白)
        }

        static void Main(string[] args)
        {
            StringBuilder test = new StringBuilder();
            test.Append("test1");
            WriteLine(test);//输出:"test1"

            StartTest1(test);
            WriteLine(test);//输出:"test1test2"

            StartTest2(test);
            WriteLine(test);//输出:"test1test2"
            ReadKey();
        }
    }

输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
test1
test1test2
test1test2

test1test2

结果分析:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
StringBuilder和string同样是引用类型,那为什么最终的StringBuilder类型值改变了呢?其实这里要纠正一下,真正改变的不是StringBuilder类型值(也就是引用的值),而是引用指向的字符数组引用指向的对象值改变了。在StringBuilder类里面封装了一个字符数组(最终的输出的就是这个字符数组,而那些操作也是对这个字符数组进行操作)。

结合上面两个实例,对于引用类型传参,从这里可以得出一个小结论:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1、在函数里面,若直接改变的是引用的值(也就是地址),那么之后的操作都不会影响到函数外面的那个变量
2、在函数里面,若直接改变的是引用指向的对象(值类型)的值(甚至更深层次的对象的值),那么就会影响到函数外面的变量

所以区分清楚改变的是引用的值还是引用指向的对象(值类型)的值是关键。

3、再来一个综合的引用类型传参的实例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    class Program
    {
        class Test
        {
            public int index;//值类型
            public StringBuilder builder;//引用类型
            public string Result{
                get{return $"{index}:{builder.ToString()}";}
            }
        }
        static void StartTest(Test test)
        {
            test.index++;
            test.builder.Append("test2");
            WriteLine(test.Result);//输出:"2:test1test2"

            test.index = new int();
            test.builder = new StringBuilder();
            test.builder.Append("test3");
            WriteLine(test.Result);//输出:"0:test3"
        }
        static void Main(string[] args)
        {
            Test test = new Test {
                index = 0,
                builder = new StringBuilder()
            };
            test.index++;
            test.builder.Append("test1");
            WriteLine(test.Result);//输出:"1:test1"

            StartTest(test);
            WriteLine(test.Result);//输出:"0:test3"
        }
    }

输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1:test1
2:test1test2
0:test3
0:test3

结果分析: 略 [若是能够明白1和2中的分析,这个应该没有问题的]

函数传参之值类型: 简单的值类型传参这里就不演示了,来一个含有引用类型的值类型传参实例(只是将上例中的struct改为了class,这样好做对比):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    class Program
    {
        struct Test
        {
            public int index;//值类型
            public StringBuilder builder;//引用类型
            public string Result{
                get{return $"{index}:{builder.ToString()}";}
            }
        }
        static void StartTest(Test test)
        {
            test.index++;
            test.builder.Append("test2");
            WriteLine(test.Result);//输出:"2:test1test2"

            test.index = new int();
            test.builder = new StringBuilder();
            test.builder.Append("test3");
            WriteLine(test.Result);//输出:"0:test3"
        }
        static void Main(string[] args)
        {
            Test test = new Test {
                index = 0,
                builder = new StringBuilder()
            };
            test.index++;
            test.builder.Append("test1");
            WriteLine(test.Result);//输出:"1:test1"

            StartTest(test);
            WriteLine(test.Result);//输出:"1:test1test2"
        }
    }

输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1:test1
2:test1test2
0:test3
1:test1test2

结果分析:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
首先应该明白,值类型以"传值"方式传递时,是一种浅拷贝,所以对于引用类型,只是复制了引用的值,副本(形参)中的引用指向的对象还是同一个。其他的自己分析应该明白。

结论: 1、无论是引用类型还是值类型,永远不会传递对象本身。涉及到一个引用类型时,要么以“引用传递”的方式(使用了ref或out关键字)传递变量,要么以“传值”的方式传递参数值(引用)。所以,通常函数传参(不论是引用类型还是值类型),都是以“传值”的方式传递的,只是要明白引用类型的值是引用本身(相当于一个索引或地址,而这个索引或地址最终指向的才是对象本身)。

2、“引用方式”传递与“传值”传递方式最大的区别就是“引用方式”要使用ref或out关键字修饰,所以以这个为标准去区分函数传参的方式(而不是以类型是引用类型还是值类型)。

3、对于传入函数的引用类型变量,最终会不会受到函数内部修改的影响,需要区分清楚函数内部改变的是引用的值还是引用指向的对象(值类型)的值。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-09-04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
理解C#语言中相等Equality 和唯一 Identity
c#有一个“Equals”方法,可以用来比较两个对象。我将试着用例子来解释等式和同一性的概念。 namespace TestEqualityDemo { class Program { static void Main(string[] args) { TestEquality test1 = new TestEquality(); test1.FirstName = "Tom";
程序你好
2018/07/20
5390
第183天:引用类型和值类型
一、内存分配 1、数值型内存分配 1 <script> 2 var num1; //这个时候不进行内存分配 3 var num3=9;//分配内存 4 var num4=num3;//会不会分配 5 6 // 这里到底分配还是不分配内存?? 7 // 答案 --分配内存 彼此拥有独立的内存空间,互不影响 8 console.log(num3); 9 console.log(num4); 10 11 num3=3333
半指温柔乐
2018/09/11
4090
C# 进行AI工程开发-基础篇
一直以来,官方口径都是尽量不要碰 CSharp 里的 unsafe 部分,以至于在大部分其它语言的程序员眼里,甚至 CSharp 程序员的眼里,CSharp 就是一个 java,做做 CRUD,捣鼓捣鼓局限于 windows 平台的 Winform 和 WPF 就行了。
郑子铭
2023/08/30
4990
C# 进行AI工程开发-基础篇
实例对比剖析c#引用参数的用法建议收藏
c#引用参数传递的深入剖析值类型的变量存储数据,而引用类型的变量存储对实际数据的引用。(这一点很重要,明白了之后就能区分开值类型和引用类型的差别)
全栈程序员站长
2022/07/15
5930
面向对象(四)-值类型与引用类型详解
类型被分为两种:值类型(整数,bool struct char 小数)和引用类型(string 数组 自定义的类,内置的类)。
孙寅
2020/06/02
9900
C#中值类型和引用类型及类型的转换
版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/article/details/52911145
空空云
2018/09/27
2.6K0
再聊一次值类型和引用类型
为什么提出这样看似很浅显的问题,是因为有次我在使用ArraySegment<byte>值类型时,有感而发。
有态度的马甲
2023/04/27
3080
再聊一次值类型和引用类型
每天学点 Go 规范 - 函数传参时,struct 应该传值还是引用
现在团队里几乎所有的代码都需要经过 Code Review(代码审查)之后才允许合入主分支。笔者在 CR 中看到了不少不适合的问题,也看到了不少值得学习的点,于是决定一点一滴地记录这些做法、经验、教训,以飨读者。如有错误,也欢迎读者不吝指正。
amc
2023/08/25
1.1K0
每天学点 Go 规范 - 函数传参时,struct 应该传值还是引用
[读书笔记]C#学习笔记八:StringBuilder与String详解及参数传递问题剖析
前言 上次在公司开会时有同事分享windebug的知识, 拿的是string字符串Concat拼接 然后用while(true){}死循环的Demo来讲解. 其中有提及string操作大量字符串效率低下的问题, 刚好自己之前也看过类似的问题, 于是便拿出来记录一下. 本文内容: 参数传递问题剖析, string与stringbuilder详解 1,参数传递问题剖析 对于C#中的参数传递,根据参数的类型可以分为四类: 值类型参数的按值传递 引用类型参数的按值传递 值类型参数的按引用传递 引用类型参数的按引用
一枝花算不算浪漫
2018/05/18
9760
【细品C++】引用
本篇文章将带你了解C++引用。引用作为C++新设计的类型,其功能与指针有所交集,在一定程度上代替了一些指针的用法,而希望本篇文章能令你引用的理解有帮助。
Crrrush
2023/06/23
1810
【细品C++】引用
【C++入门】—— C++入门 (中)_引用
前言:了解了什么是C++,我们进入了C++入门知识的命名空间,现在我们接着来讲剩下的C++入门知识讲解。
Eternity._
2024/06/14
1070
【C++入门】—— C++入门 (中)_引用
老生常谈:值类型 V.S. 引用类型
我在面试的时候经常会问一个问题:“谈谈值类型和引用的区别”。对于这个问题,绝大部分人都只会给我两个简洁的答案:“值类型分配在栈中,引用类型分配在堆中”,“在默认情况下,值类型参数传值(拷贝),引用类型参数传引用”。其实这个问题有很大的发挥空间,如果能够从内存布局、GC、互操作、跨AppDomain传递等方面展开,相信会加分不少。这篇文章独辟蹊径,从“变量”的角度讨论值类型和引用类型的区别。
蒋金楠
2023/07/10
2820
老生常谈:值类型 V.S. 引用类型
C#基础知识系列三(类和结构体、String和StringBuilder、equals和==)
   这一节主要来了解一下类和结构体之间的异同点、以及针对String和StringBuilder的用法、equals和==,其实可以看出很多地方都用到了上一节的值类型和引用类型、堆栈和装箱拆箱操作吧,慢慢的应用于实践,让理论与实践结合起来。
aehyok
2018/08/31
5260
Golang中函数传参存在引用传递吗?
官方文档已经明确说明:Go里边函数传参只有值传递一种方式,为了加强自己的理解,再来把每种传参方式进行一次梳理。
大愚
2018/09/13
2.3K0
Golang中函数传参存在引用传递吗?
C# 中的值类型与引用类型
在 C# 编程中,理解值类型和引用类型之间的区别是非常重要的,因为这直接影响到内存管理、性能优化以及编程模式的选择。本文将从基础概念出发,逐步深入探讨这两种类型的特点,并通过具体的代码示例来帮助读者更好地理解和应用它们。
Jimaks
2024/09/16
5730
内存、引用、封装、函数
内存内存分区模型代码区:存放函数体的二进制代码,由操作系统进行管理全局区:存放全局变量、静态变量和常量栈区:由编译器自动分配释放,存放函数的参数值、局部变量等堆区:由程序员分配释放,若程序员不释放,程序结束时由操作系统回收内存分区意义:不同分区存放的数据,赋予不同的生命周期,灵活编程程序运行前程序编译后,生成.exe可执行程序,未执行该程序前,分为两个区域:代码区:存放CPU执行的机器指令代码区是共享的,目的是对于频繁被执行的程序,只需要在内存中有一份代码即可代码区是只读的,防止程序意外的修改了它的指令全局
WuShF
2023/02/25
7680
内存、引用、封装、函数
C2第 1 节值类型引用类型介绍和字符串练习
C2第3节ref和out、装箱与拆箱 1、使用ref型参数时,传入的参数必须先被初始化。对out而言,必须在方法中对其完成初始化。 2、使用ref和out时,在方法的参数和执行方法时,都要加ref或out关键字。以满足匹配。 3、out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候。 装箱拆箱
静心物语313
2020/03/24
4560
[读书笔记]C#学习笔记三: C#类型详解..
前言 这次分享的主要内容有五个, 分别是值类型和引用类型, 装箱与拆箱,常量与变量,运算符重载,static字段和static构造函数. 后期的分享会针对于C#2.0 3.0 4.0 等新特性进行. 再会有三篇博客  这个系列的就会结束了. 也算是自己对园子中@Learning Hard出版的<<C#学习笔记>>的一个总结了. 博客内容基本上都是白天抽空在公司写好的了, 但是由于公司内部网络不能登录博客园所以只能够夜晚拿回来修改,  写的不好或者不对的地方也请各位大神指出. 在下感激不尽了.  1,值类型和
一枝花算不算浪漫
2018/05/18
1.3K0
由引用类型引发的概念的深入理解
我们从百度百科上面看引用的概念:引用类型 由类型的实际值引用(类似于指针)表示的数据类型。如果为某个变量分配一个引用类型,则该变量将引用(或“指向”)原始值。
公众号-利志分享
2022/04/25
2230
图解Java 中的参数传递是传值还是传引用?
值传递:传递的是实参的副本(更准确的说是实参引用的副本,因为形参接受的是对象的引用)
九转成圣
2024/04/10
1790
图解Java 中的参数传递是传值还是传引用?
相关推荐
理解C#语言中相等Equality 和唯一 Identity
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文