• C#学习笔记之简说参数


    我们在执行很多方法都要传参才能调用,同样我们写的很多方法都要接收一个参数才能完成逻辑。传参去调用别人写的方法,这好像并没有多少要注意的,只需要按要求传就可以了。但是当我们自己写的方法时,怎么设置这个参数呢?需要什么拿什么,这句话没错。但是有时候我们往往可以不需要传参。

    说到参数我们都会先分一下形参和实参。

    形参,形参就是在创建方法时括号里面声明的那个参数。你可以理解成一个“模型”。调用方法时,实参需要跟这个“模型”做对比,符合才能够传进去。也就是说实参和形参类型必须一致,需要传多个参数时,顺序也必须一致。

    实参,就是调用方法是你传进去的那个变量的值。

    也就是说,我创建方法时提供了一个壳,我方法里边的逻辑算法全都是用这个壳先顶着。如果方法一运行,它从我这里拿不到值,会给我报错,这我不干。所以当你需要调用我时,你得给我一个东西,让别人向我拿的时候,我能给到别人。还有我原本说这是个苹果,你总不能让我那个西瓜出来吧。所以,我问你拿什么,你就得给什么。壳理解为形参,因为它的样子(类型)跟实参一样。传进来的实参就是那个实实在在的东西。

    当然,在创建方法时,可以给形参赋个默认值,这样调用方法的时候就可以不传参数。

    接下来我们了解下传参。

    值参数

    按值传递,传递实参变量存储的内容。存什么传什么,值类型就传存的值,引用类型就传引用。作用:传递信息。

    我们一般的传参默认都是值传参。

     static void Main(string[] args)
            {
                int number = 1;
                Fun(number);
    
                Console.WriteLine("number={0}", number);//结果number = 1
                //number是int,值类型,在栈中的{number地址:1}
                //值传参,传值,传的是1
                //也就是Fun(number)跟Fun(1)没有区别,那么这样一看Fun(1)跟number就没有关系了,
                //所以Fun()内部怎么操作这个数值都跟number没有关系。
    
                Console.ReadKey();
            }
            static  private void Fun(int parameter)
            {
                //parameter=1
                parameter = 2;//{parameter地址:1}==>{parameter地址:2}改的是parameter
            }
    PS:值类型在栈中也是有地址的:{地址:值},引用类型在栈中:{地址:堆中数据的地址}。

    引用参数

    按引用传递,传递参数变量自身的内存地址。在创建方法时和调用方法,都需要在参数前面加上ref关键字。作用:改变数据

    static void Main(string[] args)
            {
                int number = 1;
                Fun(ref number);//引用传参必须加ref
    
    
                Console.WriteLine("number={0}", number);//结果number = 2
                //PS:值类型在栈中也是有地址的:{地址:值},引用类型在栈中:{地址:堆中数据的地址}。
                //number是int,值类型,在栈中的{number地址:1}
                //引用传参,传引用,传的是number地址
                //Fun(number地址)跟Fun(1)肯定有区别了,number地址不等于1
                //那么这样Fun(number地址)跟number能直观的看到有关系
                
                Console.ReadKey();
            }
            static  private void Fun(ref int parameter)
            {
                //方法内部修改引用参数,实质上就是修改实参变量。
                //parameter此时此刻就是number
                //parameter=1
                parameter = 2;//{number地址:1}==>{number地址:2}改的是number
            }

    输出参数

    也是按引用传递,传递参数变量自身的内存地址。在创建方法时和调用方法,都需要在参数前面加上out关键字。作用:返回结果

     static void Main(string[] args)
            {
                int number;//输出参数,传递前可以不赋值
                Fun(out number);//传递输出参数必须加out
    
    
                Console.WriteLine("number={0}", number);//结果number = 2
               
                
                Console.ReadKey();
            }
            static  private void Fun(out int parameter)
            {
                //跟引用参数的区别:1,方法内部必须为输出参数赋值,输出参数在传递之前可以不赋值
                //parameter此时此刻就是{number地址:}
    
                parameter = 2;//{number地址:}==>{number地址:2}本来没有值,赋了2.
            }

     如果有多个结果需要返回时,可以使用输出参数。

    优化传参

    有些时候我们可以不用参数。这样可以简化我们的代码,让代码看起来更简洁和清晰。

     static void Main(string[] args)
            {
                int[] numberArray = new int[10];
                numberArray = Fun(numberArray);//调用方法赋值
                //numberArray数组是引用类型,引用类型在栈中:{numberArray地址:numberArray在堆中数据的地址}
                //这里是值传递,传的是:numberArray在堆中数据的地址
            }
            /// <summary>
            /// 给数组赋值
            /// </summary>
            /// <param name="array">目标数组</param>
            /// <returns>目标数组</returns>
            static private int[] Fun(int[] array)
            {
                //array在栈中{array地址:numberArray在堆中数据的地址}
                //numberArray在堆中数据的地址==>数据1
                for (int i = 0; i < array.Length; i++)
                {
                    array[i] = i;
                }
    
                //到最后我只是把数据改变了,数据1变成了数据2:numberArray在堆中数据的地址==>数据2,
    
                //而array在栈中{array地址:numberArray在堆中数据的地址},没有任何变化。
                //甚至最后需要返回的值 numberArray在堆中数据的地址 跟传进来的一模一样。
    
                //也就是说,方法内部并不需要对 numberArray在堆中数据的地址 进行操作。要操作的是这个地址指向的那些数据。
                //所以,不需要传给我,但是又能让我拿的到就行。
                return array;
            }

    只要将numberArray声明为全局变量,那么所有的方法都能不需要通过传参随意拿到。因为numberArray是数组,而数组是引用类型。所以我们不管在哪个方法中改变了该引用(地址)在堆中的数据,那么通过同一个引用(地址),其他方法获取的都是同一份已改过的数据。

    所以以上代码可以改为

           static  int[] numberArray;
            static void Main(string[] args)
            {
    
                //Fun();在这里调这个方法会出现错误,因为这时的numberArray在栈中{numberArray地址:},没有堆中数据的地址,找不到空间给它赋值
                numberArray = new int[10];//{numberArray地址:}==>{numberArray地址:堆中数据的地址},给它在堆中开辟一块空间。并将堆中空间的地址赋该变量
                Fun();//这时再调这个方法,numberArray在栈中就变成了:{numberArray地址:堆中数据的地址}
    
            }
            /// <summary>
            /// 给数组赋值
            /// </summary>
          
            static private void Fun()
            {
                //根据numberArray堆中数据的地址找到堆中那块空间,将数据存进去
                for (int i = 0; i < numberArray.Length; i++)
                {
                    numberArray[i] = i;
                }
    
            }

     最后补充一个:

    参数数组

    创建方法时,如果遇到参数的类型确定,个数不确定的情形,参数使用参数数组。需要在方法的参数类型前面加上关键字Params。

    对于方法内部而言,就是个普通的数组。

    对于方法外部调用者而言,可以传递数组,可以传递一组数据类型相同的变量集合,可以不传值

    简化了调用者调用方法的代码。

    class Program
        {
            static  int[] numberArray;
            static void Main(string[] args)
            {
                Fun(new int[] { 1, 2, 3, 4, 5 });//可以传数组
                Fun(1, 2, 3, 4, 5 );//传一组数据类型相同的变量,报错
                Fun();//不传递参数,报错
    
                ParamsFun(new int[] { 1, 2, 3, 4, 5 });//可以传数组
                ParamsFun(1, 2, 3, 4, 5);//可以传一组数据类型相同的变量
                ParamsFun();//可以不传递参数
    
            }
           
            /// <summary>
            /// 普通方法
            /// </summary>
            /// <param name="array"></param>
            static private void Fun(int[] array)
            {
                
    
            }
    
           /// <summary>
           /// 使用参数数组的方法
           /// </summary>
           /// <param name="array"></param>
            static private void ParamsFun(params int[] array)
            {
                /* ParamsFun(1, 2, 3, 4, 5)
                 * ParamsFun()
                 * 在编译时,vs会在内部进行操作:
                 * ParamsFun(1, 2, 3, 4, 5)==>ParamsFun(new int[] { 1, 2, 3, 4, 5 })
                 * ParamsFun())==>ParamsFun(new int[] {0})
                 * 实际上最后传的都是一个int[],Params只是提醒编译器需要做这样一个操作
                 * 所以对于方法内部来说得到的都是一个int[].
                 */
    
            }
        }

    最后,学无止境,只能拼命。

  • 相关阅读:
    Windows-Redis-x64-5.0.9【感谢大佬】
    Debezium初试
    一键结束进程
    Vscode自动刷新
    从零到一搭建一个jenkins+github持续构建平台
    git项目迁移
    AWS IoT 消息代理
    解析器:request.body、request.POST、request.data
    Unity程序员的Unreal 简明教程(二,模型与材质)
    Unity程序员的Unreal 简明教程(一、旋转的BOX)
  • 原文地址:https://www.cnblogs.com/xwzLoveCshap/p/11588197.html
Copyright © 2020-2023  润新知