首页 > 分享 > [你必须知道的.NET]第十二回:参数之惑ms.translationtype: HT

[你必须知道的.NET]第十二回:参数之惑ms.translationtype: HT

跳转至主内容

此浏览器不再受支持。

请升级到 Microsoft Edge 以使用最新的功能、安全更新和技术支持。

Learn

文档

有关 Microsoft 开发人员工具和技术的深度文章

问答

经 Microsoft 审核的技术问题和解答

代码示例

Microsoft 开发人员工具和技术的代码示例库

节目

来自 Microsoft 专家的数千小时原创节目

适用于组织的 Microsoft Learn

提高团队的技术技能

访问特选资源,以提升团队技能水平,缩小技能差距。

适用于组织的 Microsoft Learn

提高团队的技术技能

访问特选资源,以提升团队技能水平,缩小技能差距。

适用于组织的 Microsoft Learn

提高团队的技术技能

访问特选资源,以提升团队技能水平,缩小技能差距。

适用于组织的 Microsoft Learn

提高团队的技术技能

访问特选资源,以提升团队技能水平,缩小技能差距。

登录

[你必须知道的.NET]第十二回:参数之惑---传递的艺术(下)

项目2021/10/20

本文内容

Author:王涛

Date:2007-7-6

©2007 Anytao.com ,原创作品,转贴请注明作者和出处。

本文将介绍以下内容:

按值传递与按引用传递深论 ref 和out 比较  参数应用浅析 

接上篇继续,『第十一回:参数之惑 ---传递的艺术(上) 』

4.2 引用类型参数的按值传递

当传递的参数为引用类型时,传递和操作的是指向对象的引用,这意味着方法操作可以改变原来的对象,但是值得思考的是该引用或者说指针本身还是按值传递的。因此,我们在此必须清楚的了解以下两个最根本的问题:

引用类型参数的按值传递和按引用传递的区别? string 类型作为特殊的引用类型,在按值传递时表现的特殊性又如何解释?

首先,我们从基本的理解入手来了解引用类型参数按值传递的本质所在,简单的说对象作为参数传递时,执行的是对对象地址的拷贝,操作的是该拷贝地址。这在本质上和值类型参数按值传递是相同的,都是按值传递。不同的是值类型的“ 值” 为类型实例,而引用类型的“ 值” 为引用地址。因此,如果参数为引用类型时,在调用方代码中,可以改变引用的指向, 从而使得原对象的指向发生改变,如例所示: 

引用类型参数的按值传递

// FileName : Anytao.net.My_Must_net // Description : The .NET what you should know of arguments. // Release : 2007/07/01 1.0 // Copyright : (C)2007 Anytao.com http://www.anytao.com using System; namespace Anytao.net.My_Must_net { class Args { public static void Main() { ArgsByRef abf = new ArgsByRef(); AddRef(abf); Console.WriteLine(abf.i); } private static void AddRef(ArgsByRef abf) { abf.i = 20; Console.WriteLine(abf.i); } } class ArgsByRef { public int i = 10; } }

因此,我们进一步可以总结为:按值传递的实质的是传递值,不同的是这个值在值类型和引用类型的表现是不同的:参数为值类型时,“ 值” 为实例本身,因此传递的是实例拷贝,不会对原来的实例产生影响;参数为引用类型时,“ 值” 为对象引用,因此传递的是引用地址拷贝,会改变原来对象的引用指向,这是二者在统一概念上的表现区别,理解了本质也就抓住了根源。关于值类型和引用类型的概念可以参考《第八回:品味类型 ---值类型与引用类型(上)-内存有理 》《第九回:品味类型 ---值类型与引用类型(中)-规则无边 》《第十回:品味类型 ---值类型与引用类型(下)-应用征途 》,相信可以通过对系列中的值类型与引用类型的3 篇的理解,加深对参数传递之惑的昭雪。

了解了引用类型参数按值传递的实质,我们有必要再引入另一个参数传递的概念,那就是:按引用传递,通常称为引用参数。这二者的本质区别可以小结为:

·         引用类型参数的按值传递,传递的是参数本身的值,也就是上面提到的对象的引用;

·         按引用传递,传递的不是参数本身的值,而是参数的地址。如果参数为值类型,则传递的是该值类型的地址;如果参数为引用类型,则传递的是对象引用的地址。

关于引用参数的详细概念,我们马上就展开来讨论,不过还是先分析一下string 类型的特殊性,究竟特殊在哪里?

关于string 的讨论,在本人拙作《第九回:品味类型 ---值类型与引用类型(中)-规则无边 》已经有了讨论,也就是开篇陈述的本文成文的历史,所以在上述分析的基础上,我认为应该更能对第九回的问题,做以更正。

string 本身为引用类型,因此从本文的分析中可知,对于形如

static void ShowInfo(string aStr){...}

的传递形式,可以清楚的知道这是按值传递,也就是本文总结的引用类型参数的按值传递。因此,传递的是aStr 对象的值,也就是aStr 引用指针。接下来我们看看下面的示例来分析,为什么string 类型在传递时表现出特殊性及其产生的原因?

// FileName : Anytao.net.My_Must_net // Description : The .NET what you should know of arguments. // Release : 2007/07/05 1.0 // Copyright : (C)2007 Anytao.com http://www.anytao.com using System; namespace Anytao.net.My_Must_net { class how2str { static void Main() { string str = "Old String"; ChangeStr(str); Console.WriteLine(str); } static void ChangeStr(string aStr) { aStr = "Changing String"; Console.WriteLine(aStr); } } }

下面对上述示例的执行过程简要分析一下:首先,string str = "Old String" 产生了一个新的string 对象,如图表示:

** **

然后执行ChangeStr(aStr) ,也就是进行引用类型参数的按值传递,我们强调说这里传递的是引用类型的引用值,也就是地址指针;然后调用ChangeStr 方法,过程aStr = "Changing String" 完成了以下的操作,先在新的一个地址生成一个string 对象,该新对象的值为"Changing String" ,引用地址为0x06 赋给参数aStr ,因此会改变aStr 的指向,但是并没有改变原来方法外str 的引用地址,执行过程可以表示为:

 

因此执行结果就可想而知,我们从分析过程就可以发现string 作为引用类型,在按值传递过程中和其他引用类型是一样的。如果需要完成ChangeStr() 调用后,改变原来str 的值,就必须使用ref 或者out 修饰符,按照按引用传递的方式来进行就可以了,届时aStr = "Changing String" 改变的是str 的引用,也就改变了str 的指向,具体的分析希望大家通过接下来的按引用传递的揭密之后,可以自行分析。

4.3 按引用传递之ref 和out

不管是值类型还是引用类型,按引用传递必须以ref 或者out 关键字来修饰,其规则是:

方法定义和方法调用必须同时显示的使用ref 或者out ,否则将导致编译错误; CRL 允许通过out 或者ref 参数来重载方法,例如: 

// FileName : Anytao.net.My_Must_net // Description : The .NET what you should know of arguments. // Release : 2007/07/03 1.0 // Copyright : (C)2007 Anytao.com http://www.anytao.com using System; namespace Anytao.net.My_Must_net._11_Args { class TestRefAndOut { static void ShowInfo(string str) { Console.WriteLine(str); } static void ShowInfo(ref string str) { Console.WriteLine(str); } } }

当然,按引用传递时,不管参数是值类型还是引用类型,在本质上也是相同的,这就是:ref 和out 关键字将告诉编译器,方法传递的是参数地址,而不是参数本身。理解了这一点也就抓住了按引用传递的本质,因此根据这一本质结论我们可以得出以下更明白的说法,这就是:

不管参数本身是值类型还是引用类型,按引用传递时,传递的是参数的地址,也就是实例的指针。 如果参数是值类型,则按引用传递时,传递的是值类型变量的引用,因此在效果上类似于引用类型参数的按值传递方式,其实质可以分析为:值类型的按引用传递方式,实现的是对值类型参数实例的直接操作,方法调用方为该实例分配内存,而被调用方法操作该内存,也就是值类型的地址;而引用类型参数的按值传递方式,实现的是对引用类型的“ 值” 引用指针的操作。例如:**  **

// FileName : Anytao.net.My_Must_net // Description : The .NET what you should know of arguments. // Release : 2007/07/06 1.0 // Copyright : (C)2007 Anytao.com http://www.anytao.com using System; namespace Anytao.net.My_Must_net { class TestArgs { static void Main(string[] args) { int i = 100; string str = "One"; ChangeByValue(ref i); ChangeByRef(ref str); Console.WriteLine(i); Console.WriteLine(str); } static void ChangeByValue(ref int iVlaue) { iVlaue = 200; } static void ChangeByRef(ref string sValue) { sValue = "One more."; } } }

如果参数是引用类型,则按引用传递时,传递的是引用的引用而不是引用本身,类似于指针的指针概念。示例只需将上述string 传递示例中的ChangeStr 加上ref 修饰即可。 

下面我们再进一步对ref 和out 的区别做以交代,就基本阐述清楚了按引用传递的精要所在,可以总结为:

相同点:从CRL 角度来说,ref 和out 都是指示编译器传递实例指针,在表现行为上是相同的。最能证明的示例是,CRL 允许通过ref 和out 来实现方法重载,但是又不允许通过区分ref 和out 来实现方法重载,因此从编译角度来看,不管是ref 还是out ,编译之后的代码是完全相同的。例如:

// FileName : Anytao.net.My_Must_net // Description : The .NET what you should know of arguments. // Release : 2007/07/03 1.0 // Copyright : (C)2007 Anytao.com http://www.anytao.com using System; namespace Anytao.net.My_Must_net._11_Args { class TestRefAndOut { static void ShowInfo(string str) { Console.WriteLine(str); } static void ShowInfo(ref string str) { Console.WriteLine(str); } static void ShowInfo(out string str) { str = "Hello, anytao."; Console.WriteLine(str); } } }

编译器将提示: “ShowInfo” 不能定义仅在 ref 和 out 上有差别的重载方法。 

不同点:使用的机制不同。ref 要求传递之前的参数必须首先显示初始化,而out 不需要。也就是说,使用ref 的参数必须是一个实际的对象,而不能指向null ;而使用out 的参数可以接受指向null 的对象,然后在调用方法内部必须完成对象的实体化。  

5.结论

完成了对值类型与引用类型的论述,在这些知识积累的基础上,本文期望通过深入的论述来进一步的分享参数传递的艺术,解开层层疑惑的面纱。从探讨问题的角度来说,参数传递的种种误区其实根植与对值类型和引用类型的本质理解上,因此完成了对类型问题的探讨再进入参数传递的迷宫,我们才会更加游刃有余。我想,这种探讨问题的方式,也正是我们追逐问题的方式,深入进入.NET 的高级殿堂是绕不开这一选择的。

下一篇:[你必须知道的.NET]第十三回:从Hello, world开始认识IL-王涛

相关知识

.NET单元测试的艺术
花之惑
15亿参数的GPT
成为花艺师之前,你必须知道这3点!
祭奠送花——老人去世送什么花?这些祭奠送花礼仪你必须知道
孔雀草盆栽生命周期详解(从萌芽到凋谢,这些关键期你必须知道)
天安门广场有个特大花篮,你知道花是咋“插”的吗?
天安门广场有个好大好大的花篮,你知道花是怎么“插”的吗?
解开达尔文的“兰花之惑”
婚礼花卉见证新娘的幸福 10个小事你必须知道

网址: [你必须知道的.NET]第十二回:参数之惑ms.translationtype: HT https://m.huajiangbk.com/newsview104761.html

所属分类:花卉
上一篇: 按园林的艺术风格分,可分为规则式
下一篇: 2013.10