一、值参数(传值参数、值传递)
指参数的种类为值参数,而非参数数据类型为值类型
1.值类型的传值参数
类似一个新声明的局部变量,或传进来的实参的一个副本
可以在方法体内重现赋值,但其在方法体内被赋值时,不会影响传进来的本体
2.引用类型的传值参数
引用类型变量存储的是实例在堆内存中的地址
(1)在方法中给形参赋了新值
引用变量作为实参传进方法后会产生一个副本(形参),形参里存的也是实参指向的对象的地址
也就是说,一开始,引用形参和引用实参,指向的是同一个实例对象
但如果在方法体内对形参进行了赋值,形参指向的会是赋给他的新对象的地址
但不会对方法外的实参产生任何影响,实参仍然指向原对象地址
(实际编程中,这种操作是非常少见的)
(2)不赋新值,只操作对象
由于形参和实参指向的都是存在堆内存中的同一个对象!!!!!!!
所以对象内的成员值会被改变
所以在方法内使用值参数,当参数为引用类型时,也可能导致方法外的东西发生改变!
这种使用在实际开发中比较少见
一般将这种方法修改了参数引用对象的值的操作,称作某个方法的副作用(side-effect)
一般来说方法还是通过返回值来发挥主作用,副作用的情况要尽量避免
二、引用参数ref(引用传递)
指参数的种类为引用参数,而非参数数据类型为引用类型
引用参数不会为传进来的实参创建副本
也就是说,引用参数直接指向实际参数的变量存储位置
关键:形参与实参完全统一为一体,参数在方法内与方法外完全一致,患难与共
形实统一,内外统一
作为调用方法时用引用传递传进来的变量,在此之前一定要有实际的赋值
且调用时在引用参数前必须加上ref关键字
1.值类型的引用参数
参数并非传进来的参数的副本,而是存在内存中同一个地址的同一个值
当引用传递的参数在方法内被赋了新值时,方法外的变量也会随之一起改变
(与C、C++中的指针有关?)
带有引用参数的方法,是用ref关键字,来显式地强调在有意地利用函数的副作用改变参数的值
在声明和调用时都要写上ref
2.引用类型的引用参数
在方法体内对引用类型的引用参数重新赋值时,方法内的形参指向了赋给他的新对象
由于对应引用传递,形参与实参是一体的,所以方法外的实参变量,也跟着指向了这个新对象
如上实验结果表明,在方法内赋值后,方法外的变量一同指向了方法内创建的新对象
方法外实参与方法内形参,哈希识别码的值完全一致,二者指向的是同一个实例对象,且在方法内被赋值时会一同改变
若使用引用类型引用参数,但不为参数赋新值,只操作实例对象的成员
这样使用的效果和引用类型值参数是完全一样的,只是内存机理不一样
实验结果发现,不对引用类型的参数赋新值,只操作字段
哈希识别码没有改变,方法内外参数指向的实例对象都没有改变,只有实例对象的成员字段被改变了
效果上与值传递的引用变量一样,但内存机理不同
值传递创建了实际参数的副本,引用传递没有创建副本
但值传递参数的本体和副本,存储的都是同一个实例在堆内存中的地址,相当于两个变量存一个地址
引用参数没有创建副本,是一个变量存一个地址
三、输出参数out(输出形参)
方法作为数据的加工厂,产物只有一个返回值
那么如果希望一个方法有多个产物,就要用输出参数
也是一种对方法副作用的利用,利用输出参数,获得除返回值之外的额外输出
输出参数和引用参数一样,不为参数创建副本
引用参数在传进方法之前要先赋值
输出参数在传进方法之前不用赋值
1.值类型的输出参数
与引用传递类似由于输出参数不创建副本,所以给参数赋值,方法体外的变量也会同时获得新值
C#已有示例:
规则:
1.输出参数在方法体里必须被赋值
2.输出参数名需要是一个已声明的变量?
3.在有输出参数的方法中,如果方法执行失败,作为输出参数传进来的变量原本的值可能会被覆盖而丢失。所以作为输出参数的已有变量,一般不需要赋初始值
2.引用类型的输出参数
与引用传递类似,方法内的参数被赋新值,指向一个新对象后,方法外作为输出参数的变量也会一同被改变,指向新对象
使用例子:方法带有尝试性质,不确定是否真的能执行
就可以用返回值装一个bool变量,用来判断是否能够执行
用输出参数out来装方法的一个或多个输出值
用来尝试性的将信息灌装进实例对象中
四、params特殊数组参数
必须是形参列表的最后一个,用params修饰
示例:数组求和函数
1.不使用params的情况
不使用params修饰符的情况下,也可以用数组名当作函数的参数
声明时不用修饰,只需要把形参类型写为带索引器[ ]的
调用:调用时参数直接写数组名,不用加索引器[ ]
2.使用params的情况
声明功能声明时使用了params修饰符,与不使用没有什么区别
但是调用方法时多了一个选择,可以不提前声明一个数组来作为参数,可以直接把想作为参数的数组的元素直接列在方法的参数列表()中,编译时会自动创建一个object类型的数组,将元素放进去作为参数传入方法
当参数类型为params数组参数时,调用时就可以输入任意个数的参数!!!!!
非常方便
C#已有示例:天天用的打印方法
当参数类型为params数组参数时,调用时可以输入任意个数的参数
所以打印方法可以一次打印任意个数的字符串
C#已有示例2:字符串分割方法
str.Split方法的参数是一个params字符串数组,参数列表中,依次写上了各个分隔符,可以写任意个数的参数,返回值也是一个字符串数组,在按顺序用分隔符切割后,方法返回切割好的各个字符串
重要注意事项
由于params数组参数调用时可写无限个参数的特性
一个方法只能有一个params数组参数!
params数组参数必须是方法的参数列表中的最后一个!
五、具名参数
是一种调用方法时的参数使用方法
参数带有名字,参数的位置不再受约束
先正常声明一个方法
调用时写上参数的名字+冒号:,参数的位置就可以不再受参数列表顺序的约束
而且这样写上参数名字的调用方法,可以
六、可选参数
声明时参数具有
声明时给参数加上
在调用时就会显示参数是可选的
不写参数就会按声明时写的默认值去执行
编程规范:不推荐使用可选参数(不如用重载?)
七、扩展方法(this参数)
用于给一个已有的、不方便修改源码的类型,添加追加方法
扩展方法必须是public static的,
编程规范:并且必须放在一个静态类(名字一般为SomeTypeExtension)中
由this修饰的参数必须是参数列表中的第一个
C#的很多强大的功能都是基于扩展方法,包括
这里涉及委托和拉姆达表达式,以后再详细学习
All方法并不在List的定义中,这是一个扩展方法,写在Linq命名空间旗下的Enumerable类中
Linq命名空间中包括:
包括
All:查询集合中是否所有元素都满足(倒A标志)
Any:查询集合汇总是否有至少一个元素满足(反E存在标志)
Average:求集合内元素的平均值
(大概里面有很多关于集合的扩展方法)