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[].
             */

        }
    }

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

原文地址:https://www.cnblogs.com/xwzLoveCshap/p/11588197.html