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