笔记来源:C#图解教程(第4版)
值参数
:通过将实参的值复制到形参的方式把数据传递下去(将变量副本传递给该方法)
系统步骤:
- 在栈中为形参分配空间
- 将实参的的值复制给形参(副本)
引用参数
:形参的参数名将作为实参变量的别名,指向相同的内存位置。
系统步骤:
- 不会为形参在栈上分配内存
- 形参的参数名将作为实参变量的别名,指向相同的内存位置(在方法中对形参的作的任何改变在方法完成后依然有效(表现在实参上))
输出参数
:用于从方法体内把数据传出到调用代码,它们的行为与引用参数非常相似
注意:
值参数
的实参不一定是变量,它可以是任何能计算成相应数据类型的表达式,以变量用作实参之前,变量必须要赋值(除输出参数),对于引用类型,变量可以被设置为一个实际的引用或者null。例如:
引用参数
在
使用时必须在方法的声明和调用中都使用ref修饰符
,实参必须是变量(需要确切的内存位置),在做实参前必须要赋值,对于引用类型,变量可以被设置为一个实际的引用或者null。
输出参数
在
使用时必须在方法的声明和调用中都使用out修饰符
,实参必须是变量(需要确切的内存位置),在方法内部,输出参数在能够被读取之前必须被赋值,这意味着参数的初始值是无关的,而且没有必要在方法调用之前为实参赋值,但在方法内部,未赋值前任何语句想要访问该实参都会报错。需要赋值后才能访问操作。
———————————————————分割线————————————————————–
一、值参数中传递
值类型
和
引用类型
注:值参数是参数传递的一种
方式
,和值类型引用类型是不同概念,不要混淆
先看代码
class MyClass
{
public int Val = 20; //初始化字段为20
}
class Program
{
static void MyMethod(MyClass f1,int f2)//值参数方式传递一个引用类型和一个值类型
{
f1.Val = f1.Val + 5; //对引用类型进行修改,方便比较
f2 = f2 + 5; //对值类型进行修改
Console.WriteLine("f1.Val:{0}, f2:{1}", f1.Val,f2);//输出显示
}
static void Main()
{
MyClass a1 = new MyClass();
int a2 = 10;
MyMethod(a1,a2);//调用方法
Console.WriteLine("f1.Val:{0}, f2:{1}", a1.Val,a2);//输出显示
}
}
代码结果:f1.Val: 25,f2:15
f1.Val: 25,f2:10
内存原理:
-
在方法被调用前,用作实参的变量a2已经在栈里了
-
在方法开始时,系统在栈中为形参分配空间,并从实参复制值。
- 因为a1是引用类型的,所以引用被复制,结果实参形参都引用堆中的同一个对象。
-
因为a2是值类型的,所以值被复制,产生了一个独立的数据项。
-
在方法的结尾,f2和对象f1的字段都被加上了5。
- 方法执行后,形参从栈中弹出。
- a2,值类型,他的值不受方法行为影响。
-
a1,引用类型,但它的值被方法的行为改变了。
二、引用参数中传递
值类型
和
引用类型
class MyClass
{
public int Val = 20; //初始化字段为20
}
class Program
{
static void MyMethod(ref MyClass f1,ref int f2)//加上ref修饰符表示以引用参数方式传递一个引用类型和一个值类型
{
f1.Val = f1.Val + 5; //对引用类型进行修改,方便比较
f2 = f2 + 5; //对值类型进行修改
Console.WriteLine("f1.Val:{0}, f2:{1}", f1.Val,f2);//输出显示
}
static void Main()
{
MyClass a1 = new MyClass();
int a2 = 10;
MyMethod(ref a1,ref a2);//调用方法
Console.WriteLine("f1.Val:{0}, f2:{1}", a1.Val,a2);//输出显示
}
}
代码结果:f1.Val: 25,f2:15
f1.Val: 25,f2:15
内存原理:
-
在方法被调用前,用作实参的变量a1、a2已经在栈里了
-
在方法的开始,形参名被设置为实参的别名。变量a1和f1引用相同的内存位置,变量a2和f2引用相同的内存位置
- 在方法执行之后,形参的名称已经失效,但是值类型a2的值和引用类型a1所指向的对象的值都被方法内的行为改变了
二、输出参数中传递
值类型
和
引用类型
class MyClass
{
public int Val = 20; //初始化字段为20
}
class Program
{
static void MyMethod(out MyClass f1,out int f2)//加上out修饰符表示以输出参数方式传递一个引用类型和一个值类型
{
f1 = new MyClass(); //创建一个类变量
f1.Val = 25; //赋值类字段
f2 = 15; //赋值int参数
}
static void Main()
{
MyClass a1 = null;
int a2;
MyMethod(out a1,out a2);//调用方法
}
}
内存原理:
-
在方法被调用前,用作实参的变量a1、a2已经在栈里了
-
在方法的开始,形参名被设置为实参的别名。你可以认为变量a1和f1指向的是相同的内存位置,也可以认为a2和f2指向的是相同的内存位置。a1和a2不在作用域之内,所以不能在MyMthod中访问。
- 在方法执行之后,形参的名称已经失效,但是值类型a2的值和引用类型a1所指向的对象的值都被方法内的行为改变了