[你必须知道的.NET]第十一回:参数之惑---传递的艺术(上)
本文将介绍以下内容:
- 按值传递与按引用传递深论
- ref和out比较
- 参数应用浅析
1. 引言
接上回《第九回:品味类型---值类型与引用类型(中)-规则无边》中,对值类型和引用类型的讨论,其中关于string类型的参数传递示例和解释,引起园友的关注和讨论,可谓一石激起千层浪。受教于装配脑袋的深切指正,对这一概念有了相当进一步的了解,事实证明是我错了,在此向朋友们致歉,同时非常感谢大家的参与,尤其是装配脑袋的不倦相告。
因此,本文就以更为清晰的角度,把我理解有误的雷区作做以深入的讨论与分析,希望通过我的一点点努力和探讨至少对如下几个问题能有清晰的概念:
- 什么是按值传递?什么是按引用传递?
- 按引用传递和按引用类型参数传递的区别?
- ref与out在按引用传递中的比较与应用如何?
- param修饰符在参数传递中的作用是什么?
2. 参数基础论
简单的来说,参数实现了不同方法间的数据传递,也就是信息交换。Thinking in Java的作者有过一句名言:一切皆为对象。在.NET语言中也是如此,一切数据都最终抽象于类中封装,因此参数一般用于方法间的数据传递。例如典型的Main入口函数就有一个string数组参数,args是函数命令行参数。通常参数按照调用方式可以分为:形参和实参。形参就是被调用方法的参数,而实参就是调用方法的参数。例如:
using System;public class Arguments {public static void Main(string [] args){string myString = "This is your argument.";//myString是实际参数 ShowString(myString);}private void ShowString(string astr){Console.WriteLine(astr);} }
由上例可以得出以下几个关于参数的基本语法:
- 形参和实参必须类型、个数与顺序对应匹配;
- 参数可以为空;
- 解析Main(string [] args),Main函数的参数可以为空,也可以为string数组类,其作用是接受命令行参数,例如在命令行下运行程序时,args提供了输入命令行参数的入口。
- 另外,值得一提的是,虽然CLR支持参数默认值,但是C#中却不能设置参数默认值,这一点让我很郁闷,不知为何?不过可以通过重载来变相实现,具体如下:
static void JudgeKind(string name, string kind) {Console.WriteLine("{0} is a {1}", name, kind); }static void JudgeKind(string name) {//伪代码if(name is person){Console.WriteLine(name, "People");} }
这种方法可以扩展,可以实现更多个默认参数实现,不过,说实话有些多此一举,不够灵活,不爽不爽。
3. 传递的基础
接下来,我们接上面的示例讨论,重点将参数传递的基础做以交代,以便对参数之惑有一个从简入繁的演化过程。我们以基本概念的形式来一一列出这些基本概念,先混个脸儿熟,关于形参、实参、参数默认值的概念就不多做交代,参数传递是本文的核心内容,将在后文以大量的笔墨来阐述。所以接下来的概念,我们就做以简单的引入不花大量的精力来讨论,主要包括:
3.1 泛型类型参数
泛型类型参数,可以是静态的,例如MyGeneric<int>;也可以是动态的,此时它其实就是一个占位符,例如MyGeneric<T>中的T可以是任何类型的变量,在运行期动态替换为相应的类型参数。泛型类型参数一般也以T开头来命名。
3.2 可变数目参数
一般来说参数个数都是固定的,定义为集群类型的参数可以实现可变数目参数的目的,但是.NET提供了更灵活的机制来实现可变数目参数,这就是使用param修饰符。可变数目参数的好处就是在某些情况下可以方便的提供对于参数个数不确定情况的实现,例如计算任意数字的加权和,连接任意字符串为一个字符串等。我们以一个简单的示例来展开对这个问题的论述,为:
在此基础上,我们将使用param关键字实现可变数目参数的规则和使用做以小结为:
- param关键字的实质是:param是定制特性ParamArrayAttribute的缩写(关于定制特性的详细论述请参见第三回:历史纠葛:特性和属性),该特性用于指示编译器的执行过程大概可以简化为:编译器检查到方法调用时,首先调用不包含ParamArrayAttribute特性的方法,如果存在这种方法就施行调用,如果不存在才调用包含ParamArrayAttribute特性的方法,同时应用方法中的元素来填充一个数组,同时将该数组作为参数传入调用的方法体。总之就是param就是提示编译器实现对参数进行数组封装,将可变数目的控制由编译器来完成,我们可以很方便的从上述示例中得到启示。例如:
static void ShowAgeSum(string team, params int[] ages){...}
实质上是这样子:
static void ShowAgeSum(string team, [ParamArrayAttribute] int[] ages){...}
- param修饰的参数必须为一维数组,事实上通常就是以群集方式来实现多个或者任意多个参数的控制的,所以数组是最简单的选择;
- param修饰的参数数组,可是是任何类型。因此,如果需要接受任何类型的参数时,只要设置数组类型为object即可;
- param必须在参数列表的最后一个,并且只能使用一次。
4. 深入讨论,传递的艺术
默认情况下,CRL中的方法都是按值传递的,但是在具体情况会根据传递的参数情况的不同而有不同的表现,我们在深入讨论传递艺术的要求下,就是将不同的传递情况和不同的表现情况做以小结,从中剥离出参数传递复杂表现之内的实质所在。从而为开篇的几个问题给出清晰的答案。
4.1 值类型参数的按值传递
首先,参数传递根据参数类型分为按值传递和按引用传递,默认情况下都是按值传递的。按值传递主要包括值类型参数的按值传递和引用类型参数的按值传递。值类型实例传递的是该值类型实例的一个拷贝,因此被调用方法操作的是属于自己本身的实例拷贝,因此不影响原来调用方法中的实例值。以例为证:
using System; namespace My_Must_net {class Args{public static void Main(){int a = 10;Add(a);Console.WriteLine(a);}private static void Add(int i){i = i + 10;Console.WriteLine(i);}} }
[你必须知道的.NET]第十一回:参数之惑---传递的艺术(上)相关推荐
- [你必须知道的.NET]第二十一回:认识全面的null
<你必须知道的.NET>网站 | Anytao技术博客 [你必须知道的.NET]第二十一回:认识全面的null 发布日期:2008.7.31 作者:Anytao © 2008 Anyta ...
- 【转】[你必须知道的.NET]第二十一回:认识全面的null
引用自:http://www.cnblogs.com/anytao/category/155694.html 作者:Anytao . 说在,开篇之前 null. nullable.??运算符.null ...
- [你必须知道的.NET]第二十七回:interface到底继承于object吗?
<你必须知道的.NET>网站 | Anytao技术博客 [你必须知道的.NET]第二十七回:interface到底继承于object吗? 发布日期:2009.03.05 作者:Anyta ...
- [你必须知道的css系列]第一回:丰富的利器2:CSS选择符之子选择符、相邻选择符...
对了,接下来要讲的属性选择符,相邻选择符,子对象选择符可能大家稍微有点陌生了,这当然也是有原因的,因为IE6及以下的浏览器并不支持这几个选择符,而 大多数从事这方面工作的技术人员,多数时候还是主要考虑 ...
- [你必须知道的.NET] 第五回:深入浅出关键字---把new说透(转载)
[你必须知道的.NET] 第五回:深入浅出关键字---把new说透 作者:Anytao 本文将介绍以下内容: 面向对象基本概念 new关键字深入浅出 对象创建的内存管理 1. 引言 园子里好像没有或者 ...
- [你必须知道的.NET]第十三回:从Hello, world开始认识IL
发布日期:2007.7.22 作者:Anytao ©2007 Anytao.com ,原创作品,转贴请注明作者和出处. 本文将介绍以下内容: IL代码分析方法 Hello, world历史 .NET学 ...
- [你必须知道的.NET]第十二回:参数之惑---传递的艺术(下)
本文将介绍以下内容: 按值传递与按引用传递深论 ref和out比较 参数应用浅析 接上篇继续,『第十一回:参数之惑---传递的艺术(上)』 4.2 引用类型参数的按值传递 当传递的参数为引用类型时,传 ...
- [你必须知道的.NET]第二十回:学习方法论
本文,源自我回答刚毕业朋友关于.NET学习疑惑的回复邮件. 本文,其实早计划在<你必须知道的.NET>写作之初的后记部分,但是因为个中原因未能如愿,算是补上本书的遗憾之一. 本文,作为[& ...
- [你必须知道的.NET]第二十三回:品味细节,深入.NET的类型构造器
1 引言 今天Artech兄在<关于Type Initializer和 BeforeFieldInit的问题,看看大家能否给出正确的解释>一文中让我们认识了一个关于类型构造器调用执行的有趣 ...
最新文章
- 线下活动【西安站】用Leangoo做Scrum敏捷开发实战课(免费)
- python手机版怎么运行项目或脚本-把Python脚本放到手机上定时运行
- 【转】C# using的三种使用方法
- Oracle安装笔记
- Greenplum【问题记录 01】资源组配置后GPCC用户无法认证登录
- OpenCV学习(二十二) :反向投影:calcBackProject(),mixChannels()
- [转载]XSS 攻擊常用腳本
- 经验 | CVPR 2021 Area Chair:谈CVPR 2021审稿
- k8s停止服务_Kubernetes 服务部署最佳实践(二) 如何提高服务可用性
- 解决 IntelliJ 乱码问题
- RPC与Apache Thift
- 使用 OpenSSL 创建ssl证书
- Dynamic CRM 2016 IFD配置(6)Claims-based认证-外部访问配置
- http返回码301、302、307、305含义和区别
- Inventory 物料库存 mtl_transactions_interface 开发[转]
- 计算机一级wps表格函数,WPS表格函数学习之公式大全(字母顺序).pdf
- SQLyog到期了处理
- 考研英语单词-近义词分类-Fifth Day
- mybtisset where tirm 等标签的作用
- cad考试题库绘图题答案_CAD考试试题库及参考答案
热门文章
- 理解 Delphi 的类(四) - 初识类的事件
- Android改变移动网络ip地址,Android之获取移动网络ip
- python列表中的冒号_python 列表中[ ]中冒号‘:’的作用
- 数据库知识点补充::约束
- php网站开发案例教程ppt,php网站开发案例教程》课件.ppt
- 编写python程序输出图形_python 图形化编程---文本输入框
- python中常用的序列化模块_Python常用模块之pickle——对象序列化
- linux根文件系统配置,嵌入式Linux的Cramfs根文件系统配置的解决方案
- php api接口调试,PHP进行API接口测试
- eeglab中文教程系列(9)-绘制ERP图像