《C#图解教程》拾遗六-方法

目录

一、局部变量

1、对比实例字段和局部变量

2、var关键字

二、局部常量

1、特征

2、格式

三、控制流

跳转语句

四、局部函数

五、参数

1、形参

2、实参

位置参数

六、值参数

七、引用参数

八、引用类型作为值参数和引用参数

1、将引用类型作为值参数传递

2、将引用类型对象作为引用参数传递

九、输出参数

十、参数数组

1、方法调用

2、将数组作为实参

十一、参数类型总结

十二、ref局部变量和ref返回

1、ref局部变量

 2、ref返回

十三、方法重载

十四、命名参数

十五、可选参数

 十六、栈帧

 十七、递归


一、局部变量

1、对比实例字段和局部变量

实例字段与局部变量区别
实例字段 局部变量
生存期 实例被创建开始,到实例没有用时结束 在块中被声明开始,到块完成执行结束
隐式初始化 初始化为实例的默认值 没有隐式初始化,若不被初始化,编译器报错
存储区域 因为是类成员,不论是引用类型还是值类型,一律存储在堆内存

值类型存储在栈,引用类型存储在堆

2、var关键字

  1. 只能用于局部变量,不能用于字段声明;
  2. 只能在初始化变量时使用;
  3. 一旦编译器推断出类型,就固定且不可改变;
  4. 不像JavaScript中的var可以引用不同的类型,C#的var是从表达式右边推断出变量类型,因此var并不改变C#的强类型性质。

二、局部常量

1、特征

  1. 在声明时必须初始化;
  2. 声明后不能改变;

2、格式

c31d538d2f3b4d93a918ff5eb4a672c1.png

其中,const是关键字,Value初始化值是必须的。

初始化值是在编译时期决定的,可以是null引用,但不能是某对象的引用,因为对象的引用是在运行时决定的。

三、控制流

跳转语句

  • break   跳出当前循环
  • continue   到当前循环的顶部
  • goto   到一个命名的语句
  • return   返回到调用方法继续执行

四、局部函数

在一个方法内部嵌套的另一个方法就是局部函数。

与局部变量不同,局部函数可写在使用处的任何地方,也就是说,使用局部函数的代码可以先于局部函数的定义。

class LocalFunction
{
    public void MethodWithLocalFunction()
    {
        int result = MyLocalFunction(6);
        Console.WriteLine($"Results of local function call:{result}");

        int MyLocalFunction(int z1)     //声明局部函数
        {
            return z1 * 5;
        }
    }
}

五、参数

1、形参

形参是局部变量,声明在方法参数列表而不是方法体中。

  • 形参是变量,因此可以读写;
  • 与局部变量不同,形参方法体外面已定义,在方法体开始之前初始化,输出参数除外;
  • 参数列表中可以有任意数目的形参,彼此以逗号隔开;

2、实参

实参是初始化形参的表达式或变量。

  • 实参位于调用函数的参数列表中;
  • 实参必须与对应位置的形参类型保持一致,或者编译器能够推断出实参类型与对应位置形参类型一致;

位置参数

实参的数量必须与形参保持一致,且对应位置的类型也必须保持一致,这种形式的参数称为位置参数。

class LocationParameter
{
    public int Sum(int x,int y)
    {
        return x + y;
    }

    public float Avg(float f1,float f2)
    {
        return (f1 + f2) / 2;
    }

    public void ConsoleOut()
    {
        int someInt = 6;
        Console.WriteLine($"Newflash: Sum:5 + {someInt} = {Sum(5, 6)}");
        Console.WriteLine($"Newflash: Avg:(5 + {someInt})/2 = {Avg(5, 6)}");
    }
}

其中,调用Avg函数时,编译器已经将5和someInt隐式转换为float类型了。

六、值参数

值参数是把实参的值复制给形参。

方法被调用时执行如下操作:

  • 在栈中为形参分配空间;
  • 将实参的值复制给形参;

注意:值类型与值参数没有关系,值类型是指类型本身包含其值。

class MyValueParameterClass
{
    public int Val = 20;
}
public class ValueParameter
{
    static void MyMethod(MyValueParameterClass f1,int f2)
    {
        f1.Val = f1.Val + 5;
        f2 = f2 + 5;
        Console.WriteLine($"f1.Val={f1.Val}, f2={f2}");
    }

    static void Main()
    {
        MyValueParameterClass a1 = new MyValueParameterClass();
        int a2 = 10;

        MyMethod(a1, a2);
        Console.WriteLine($"a1.Val={a1.Val}, a2={a2}");
    }
}

执行结果: 

 上图展示了实参和形参在方法执行的不同阶段的值,表明如下3点:

  • 在方法调用前,用作实参的变量a2已经在栈里了;
  • 在方法开始时,系统在栈中为形参分配空间,并从实参复制值
    • 因为a1是引用类型的,所以引用被复制,结果实参和形参都引用堆中的同一个对象;
    • 因为a2是值类型的,所以值被复制,产生了一个独立的数据项;
  • 在方法的结尾,f2和对象f1的字段都被加上了5
    • 方法执行后,形参从栈中弹出;
    • a2,值类型,它的值不受方法行为的影响;
    • a1,引用类型,但它的值被方法的行为改变了;

七、引用参数

使用引用参数时,必须在方法的声明和调用中都使用ref修饰符。

实参必须是变量,在用作实参前必须被赋值。如果是引用类型变量,可以赋值为一个引用或null。

与值参数相比,引用参数有以下特点:

  • 不会在栈上为形参分配内存;
  • 形参的参数名将作为实参变量的别名,指向相同的内存位置。
class MyRefParameterClass
{
    public int Val = 20;
}

class RefParameter
{
    static void MyMethod(MyRefParameterClass f1,int f2)
    {
        f1.Val = f1.Val + 5;
        f2 = f2 + 5;
        Console.WriteLine($"f1.Val={f1.Val}, f2={f2}");
    }

    static void Main()
    {
        MyRefParameterClass a1 = new MyRefParameterClass();
        int a2 = 10;

        MyMethod(a1, a2);
        Console.WriteLine($"a1.Val={a1.Val}, a2={a2}");
    }
}

执行结果: 

 上图阐明了引用参数在方法执行的不同阶段实参和形参的值:

  • 在方法调用之前,将要被用作实参的变量a1和a2已经在栈里了;
  • 在方法的开始,形参名被设置为实参的别名,变量a1和f1引用相同的内存位置,a2和f2引用相同的内存位置;
  • 在方法的结束位置,f2和f1的对象的字段都被加上了5;
  • 方法执行之后,形参的名称已经失效,但是值类型a2的值和引用类型a1所指向的对象的值都被方法内的行为改变了;

八、引用类型作为值参数和引用参数

1、将引用类型作为值参数传递

如果在方法内创建一个新对象并赋值给形参,将切断形参与实参之间的关联,并且在方法调用结束后,新对象也将不复存在。

class MyRefAsValueParamClass
{
    public int Val = 20;
}
class RefAsValueParam
{
    static void MyMethod(MyRefAsValueParamClass f1)
    {
        f1.Val = 50;
       
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值