[你必须知道的.NET] 第十一回:参数之惑---传递的艺术(上)
系列文章导航:
[你必须知道的.NET] 第四回:后来居上:class和struct
[你必须知道的.NET] 第五回:深入浅出关键字---把new说透
[你必须知道的.NET] 第六回:深入浅出关键字---base和this
[你必须知道的.NET] 第七回:品味类型---从通用类型系统开始
[你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理
[你必须知道的.NET] 第九回:品味类型---值类型与引用类型(中)-规则无边
[你必须知道的.NET] 第十回:品味类型---值类型与引用类型(下)-应用征途
[你必须知道的.NET] 第十一回:参数之惑---传递的艺术(上)
[你必须知道的.NET] 第十二回:参数之惑---传递的艺术(下)
[你必须知道的.NET] 第十三回:从Hello, world开始认识IL
[你必须知道的.NET] 第十四回:认识IL代码---从开始到现在
[你必须知道的.NET] 第十六回:深入浅出关键字---using全接触
[你必须知道的.NET]第二十二回:字符串驻留(上)---带着问题思考
[你必须知道的.NET]第三十二回,深入.NET 4.0之,Tuple一二
本文将介绍以下内容:
• 按值传递与按引用传递深论
• ref和out比较
• 参数应用浅析
1. 引言
接上回《第九回:品味类型---值类型与引用类型(中)-规则无边》中,对值类型和引用类型的讨论,其中关于string类型的参数传递示例和解释,引起园友的关注和讨论,可谓一石激起千层浪。受教于装配脑袋的深切指正,对这一概念有了相当进一步的了解,事实证明是我错了,在此向朋友们致歉,同时非常感谢大家的参与,尤其是装配脑袋的不倦相告。
因此,本文就以更为清晰的角度,把我理解有误的雷区作做以深入的讨论与分析,希望通过我的一点点努力和探讨至少对如下几个问题能有清晰的概念:
• 什么是按值传递?什么是按引用传递?
• 按引用传递和按引用类型参数传递的区别?
• ref与out在按引用传递中的比较与应用如何?
• param修饰符在参数传递中的作用是什么?
2. 参数基础论
简单的来说,参数实现了不同方法间的数据传递,也就是信息交换。Thinking in Java的作者有过一句名言:一切皆为对象。在.NET语言中也是如此,一切数据都最终抽象于类中封装,因此参数一般用于方法间的数据传递。例如典型的Main入口函数就有一个string数组参数,args是函数命令行参数。通常参数按照调用方式可以分为:形参和实参。形参就是被调用方法的参数,而实参就是调用方法的参数。例如:
Code
由上例可以得出以下几个关于参数的基本语法:
• 形参和实参必须类型、个数与顺序对应匹配;
• 参数可以为空;
• 解析Main(string [] args),Main函数的参数可以为空,也可以为string数组类,其作用是接受命令行参数,例如在命令行下运行程序时,args提供了输入命令行参数的入口。
• 另外,值得一提的是,虽然CLR支持参数默认值,但是C#中却不能设置参数默认值,这一点让我很郁闷,不知为何?不过可以通过重载来变相实现,具体如下:
Code
3. 传递的基础
接下来,我们接上面的示例讨论,重点将参数传递的基础做以交代,以便对参数之惑有一个从简入繁的演化过程。我们以基本概念的形式来一一列出这些基本概念,先混个脸儿熟,关于形参、实参、参数默认值的概念就不多做交代,参数传递是本文的核心内容,将在后文以大量的笔墨来阐述。所以接下来的概念,我们就做以简单的引入不花大量的精力来讨论,主要包括:
3.1 泛型类型参数
泛型类型参数,可以是静态的,例如MyGeneric<int>;也可以是动态的,此时它其实就是一个占位符,例如MyGeneric<T>中的T可以是任何类型的变量,在运行期动态替换为相应的类型参数。泛型类型参数一般也以T开头来命名。
3.2 可变数目参数
一般来说参数个数都是固定的,定义为集群类型的参数可以实现可变数目参数的目的,但是.NET提供了更灵活的机制来实现可变数目参数,这就是使用param修饰符。可变数目参数的好处就是在某些情况下可以方便的提供对于参数个数不确定情况的实现,例如计算任意数字的加权和,连接任意字符串为一个字符串等。我们以一个简单的示例来展开对这个问题的论述,为: