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所指向的对象的

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

相关推荐
侠客行031717 小时前
Mybatis连接池实现及池化模式
java·mybatis·源码阅读
蛇皮划水怪17 小时前
深入浅出LangChain4J
java·langchain·llm
子兮曰17 小时前
OpenClaw入门:从零开始搭建你的私有化AI助手
前端·架构·github
吴仰晖18 小时前
使用github copliot chat的源码学习之Chromium Compositor
前端
1024小神18 小时前
github发布pages的几种状态记录
前端
老毛肚19 小时前
MyBatis体系结构与工作原理 上篇
java·mybatis
风流倜傥唐伯虎20 小时前
Spring Boot Jar包生产级启停脚本
java·运维·spring boot
不像程序员的程序媛20 小时前
Nginx日志切分
服务器·前端·nginx
Yvonne爱编码20 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
Re.不晚20 小时前
JAVA进阶之路——无奖问答挑战1
java·开发语言