C# 方法(值参数和引用参数)

本章内容:

方法的结构

方法体内部的代码执行

局部变量

局部常量

控制流

方法调用

返回值

返回语句和void方法

局部函数

参数

值参数

引用参数

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

输出参数

参数数组

参数类型总结

方法重载

命名参数

可选参数

栈帧

递归

值参数

参数有几种,各自以略微不同的方式从方法传入或传出数据。到目前为止,你看到的这种类

型是默认的类型,称为值参数(valueparameter)。

当你使用值参数时,通过将实参的值复制到形参的方式把数据传递给方法。方法被调用时,

系统执行如下操作。

在栈中为形参分配空间。

将实参的值复制给形参。

值参数的实参不一定是变量,它可以是任何能计算成相应数据类型的表达式。例如,下面的

代码展示了两个方法调用。在第一个方法调用中,实参是float类型的变量;在第二个方法调用

中,实参是计算成float的表达式。

csharp 复制代码
float func1(float val)     //申明方法
{
    float j=2.6F;
    float k=5.1F;
    ...
}
csharp 复制代码
float fValue1=func1(k);     //方法调用
float fValue2=func1((k+j)/3);//方法调用

用作实参之前,变量必须被赋值(除非是输出参数,稍后会介绍)。对于引用类型,变量可

以被设置为一个实际的引用或null。

说明 所谓值类型就是指类型本身包含其值。不要把值类型

和这里介绍的值参数混淆,它们是完全不同的两个概念。值参数是把实参的值复制给

形参。

例如,下面的代码展示了一个名为MyMethod的方法,它有两个参数:一个MyClass类型的变

量和一个int。

方法为类的int类型字段和参数都加上5。

你可能还注意到MyMethod使用了修饰符static,我们还没有解释过这个关键字,现在你

可以忽略它。

csharp 复制代码
class MyClass
{
    public int Val=20;      //初始化字段为20
}

class Program
{
    static void MyMethod(MyClass f1,int f2)
    {
        f1.Val=f1.Val+5;     //参数的字段加5
        f2    =f2+5;         //另一参数加5
    }

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


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

图6-7展示了实参和形参在方法执行的不同阶段的值,它表明了以下3点。

在方法被调用前,用作实参的变量a2已经在栈里了。

在方法开始时,系统在栈中为形参分配空间,并从实参复制值。

因为a1是引用类型的,所以引用被复制,结果实参和形参都引用堆中的同一个对象。

因为a2是值类型的,所以值被复制,产生了一个独立的数据项。

在方法的结尾,f2和对象f1的字段都被加上了5。

方法执行后,形参从栈中弹出。

到a2,值类型,它的值不受方法行为的影响。

a1,引用类型,但它的值被方法的行为改变了。

第二种参数类型称为引用参数。

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

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

用或null。

例如,下面的代码阐明了引用参数的声明和调用的语法:

csharp 复制代码
void MyMethod(ref int val)   //方法申明
{...}

int y=1;                     //实参变量
MyMethod(ref y);             //方法调用


MyMethod(ref 3+5);           //出错了

不会在栈上为形参分配内存。

形参的参数名将作为实参变量的别名,指向相同的内存位置。

由于形参名和实参名指向相同的内存位置,所以在方法的执行过程中对形参做的任何改变在

方法完成后依然可见(表现在实参变量上)。

说明 记住要在方法的声明和调用上都使用ref关键字。

例如,下面的代码再次展示了方法MyMethod,但这一次参数是引用参数而不是值参数。

csharp 复制代码
class MyClass
{
    public int Val=20;       //初始化字段为20
}

class Program
{
    static void MyMethod(ref MyClass f1,ref int f2)
    {
        f1.Val=f1.Val+5;       //参数的字段加5
        f2    =f2+5;           //另一参数加5
        Console.WriteLine($"f1.Val:{f1.Val},f2:{f2}");
    }

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



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

注意,不管MyClass对象f1是否是通过ref传递给方法,fl.val的值都是相同的。稍后会

对此进行详细的讨论。

图6-8阐明了在方法执行的不同阶段实参和形参的值。

在方法调用之前,将要被用作实参的变量a1和a2已经在栈里了。

在方法的开始,形参名被设置为实参的别名。变量a1和f1引用相同的内存位置,a2和

f2引用相同的内存位置。

在方法的结束位置,f2和f1的对象的字段都被加上了5。

方法执行之后,形参的名称已经失效,但是值类型a2的值和引用类型a1所指向的对象的

值都被方法内的行为改变了。

相关推荐
天上掉下来个程小白19 分钟前
缓存套餐-01.Spring Cache介绍和常用注解
java·redis·spring·缓存·spring cache·苍穹外卖
CodeCraft Studio38 分钟前
国产Excel处理控件Spire.XLS系列教程:C# 将Excel文件转换为Markdown格式
c#·excel
揣晓丹43 分钟前
JAVA实战开源项目:健身房管理系统 (Vue+SpringBoot) 附源码
java·vue.js·spring boot·后端·开源
编程轨迹_44 分钟前
使用 Spring 和 Redis 创建处理敏感数据的服务
java·开发语言·restful
奔驰的小野码1 小时前
SpringAI实现AI应用-自定义顾问(Advisor)
java·人工智能·spring boot·spring
奔驰的小野码1 小时前
SpringAI实现AI应用-使用redis持久化聊天记忆
java·数据库·人工智能·redis·spring
CodeCraft Studio1 小时前
报表控件stimulsoft教程:使用 JoinType 关系参数创建仪表盘
前端·ui
裁二尺秋风1 小时前
k8s(11) — 探针和钩子
java·容器·kubernetes
ᥬ 小月亮2 小时前
Uniapp编写微信小程序,使用canvas进行绘图
微信小程序·uni-app·c#
一方~2 小时前
XML语言
xml·java·web