02010602 方法02-值参数、引用参数、输出参数、参数数组
zhezhongyun 2025-10-19 15:35 4 浏览
02010602 方法02-值参数、引用参数、输出参数、参数数组、ref局部变量和ref返回
- 方法的参数是一个特殊变量
1. 形参
- 形参 → 是局部变量,它声明在方法的参数列表中,而不是方法体中。
public void MyFunc(int a, int b)
↑
形参声明
说明:
1. 形参是变量,因此它们有类型和名称,并能被写入和读取。
2. 和方法体中局部变量不同,参数在方法体的外面定义并在方法开始之前初始化(输出参数除外)。
3. 形参列表中可以有任意数目的形参声明,它们用","隔开。
2. 实参
- 当调用一个方法时,形参的值必须在方法的代码开始之前初始化,用于初始化形参的表达式或变量称为实参。
- 实参的数量必须和形参的数量一致,并且每个实参的类型也必须和所对应的形参类型一致,这种形式的参数称之为位置参数。
public void MyFunc(int a, int b); // 定义形参
MyFunc(10,20); // 实参在调用方法时给形参初始化
说明:
1. 实参位于方法调用的参数列表中。
2. 实参必须与对应形参的个数,类型相匹配。如果编译器能把实参隐式的转换为形参的类型也可以。后续章节会讲解。
3. 当方法被调用时,每个实参的值都被用于初始化相应的形参,方法体随后被执行。
3. C#中方法参数的四种类型
- 值参数 → 不加任何修饰符,是默认的类型。
- 引用参数 → 以ref修饰符声明
- 输出参数 → 以out修饰符声明
- 数组型参数 → 以params修饰符声明
4. 值参数
- 值参数是方法默认的参数类型,当使用值参数时,将实参的值复制到形参的方式把数据传递给方法。方法被调用时,系统执行如下操作:
- 在栈中为形参分配空间
- 将实参的值复制给形参
- ※学习本章节注意区分值类型和值参数,这是两个概念※
- 值类型 → 前面在第4章节提到,值类型就是类型本身包含其值。
- 值参数 → 值方法默认的参数类型,是将实参的值复制一份给到形参。
- 值类型和值参数是两个不同的概念,不区分这两个概念本章结根本看不懂。
4.1 值参数的实参
- 值参数的的实参可以是任何能计算成相应数据类型的表达式,也可以是变量。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo01
{
class Program
{
static void Main(string[] args)
{
MyFunc01(5-2); // 实参是表达式
MyFunc01(10); // 实参是具体的值
int myInt = 20;
MyFunc01(myInt); // 实参是变量
Console.ReadLine();
}
static void MyFunc01(int a)
{
Console.WriteLine(a);
}
}
}
控制台输出:
3
10
20
说明:
1. 值参数的实参如果是变量,在这个变量被用作实参之前,必须被赋值。
2. 在MyFunc01方法调用时,首先在栈中为形参int a分配内存空间,然后a = 实参复制一份的值。
4.2 值参数的实参是将值复制一份传递给形参
- 调用方法如果用的值参数的实参,可以在方法体中更改该值。但当控制流回到方法调用处时,并不会保留该值(也就是说变量或者表达式用作实参之前是什么,方法调用完之后还是什么)。
// 假设我们想将变量a = 1, 变量b = 2的值互换,是否可以通过值参数来实现?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo01
{
class Program
{
static void Main(string[] args)
{
int myInt01 = 10;
int myInt02 = 20;
Console.WriteLine(#34;myInt01在用作值参数之前是{myInt01},myInt02在用作值参数之前是{myInt02}");
Swap(myInt01, myInt02);
Console.WriteLine(#34;myInt01在用作值参数之后是{myInt01},myInt02在用作值参数之后是{myInt02}");
Console.ReadLine();
}
static void Swap(int x, int y)
{
Console.WriteLine(#34;调用方法时传递的是实参复制的值,此时x = {x},y = {y}");
int temp = x;
x = y;
y = temp;
Console.WriteLine(#34;我在方法体内部将实参传入的值进行了交换,此时x = {x},y = {y}");
}
}
}
控制台输出:
myInt01在用作值参数之前是10,myInt02在用作值参数之前是20
调用方法时传递的是实参复制的值,此时x = 10,y = 20
我在方法体内部将实参传入的值进行了交换,此时x = 20,y = 10
myInt01在用作值参数之后是10,myInt02在用作值参数之后是20
说明:当使用值参数时,是将实参的值复制一份,传递给形参。使用值参数调用方法,在方法内部,只能实现实参复制出来的值的交换,而无法实现实参本身的交换。
※注意本代码段表述的内容可能不准确※
4.3 值参数的实参是引用类型
- 值参数的实参是引用类型,所以引用被复制,结果实参和形参都引用堆中同一个对象。方法体中对该对象的改变会影响到方法体外的实参。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo01
{
class MyClass
{
public int var = 20;
}
class Program
{
static void MyFunc(MyClass f1, int f2)
{
f1.var = f1.var + 5;
f2 = f2 + 5;
Console.WriteLine(#34;方法调用前f1.var:{f1.var},f2:{f2}");
}
static void Main(string[] args)
{
MyClass a1 = new MyClass();
int a2 = 10;
MyFunc(a1, a2);
Console.WriteLine(#34;方法调用后f1.var:{a1.var},f2:{a2}");
Console.ReadLine();
}
}
}
控制台输出:
方法调用前f1.var:25,f2:15
方法调用后f1.var:25,f2:10
说明:
1. 在方法开始调用之前,作用实参的变量a2已经在栈里面了。
2. 在方法开始调用时,系统在栈中为形参f1和f2分配内存空间,并且从实参复制值。
2.1 因为变量a1是引用类型,用作参数时将引用复制一份给到形参f1,此时实参a1和形参f1都引用堆中同一个对象。
2.2 以为变量a2是值类型,所以值被复制一份给到形参。
3. 在MyFunc方法中,对象f1的字段加5,f2的值加5。
3.1 方法执行后,形参从栈中弹出。
3.2 a2是值类型,它的值不收方法行为的影响,方法行为影响的传递给形参那一份复制的值。
3.3 a1是引用类型,它的值被方法改变了。
5. 引用参数
- 使用引用参数,在方法定义和调用的时候都必须显式的使用ref修饰符。
- 使用引用参数,实参必须是变量,并且这个变量必须被赋值。如果这个变量是引用类型,可以赋值为一个引用或null。
void MyFunc(ref int val) // 方法声明
{
...
}
int y = 1; // 实参变量
MyFunc(ref y); // 方法调用
// MyFunc(ref 3+5); // 错误写法,实参必须是变量,而不能是表达式。
- 引用参数的特点
- 调用引用参数的方法时,并不会给形参在栈中分配内存。
- 形参的参数名将作为实参变量的别名,指向相同的内存位置。
- 由于形参名和实参名指向相同的内存位置,所以在方法的执行过程中对形参做的任何修改在方法完成后依然可见。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo01
{
class Program
{
static void Swap(ref int x, ref int y)
{
Console.WriteLine(#34;x = {x},y = {y}");
int temp = x;
x = y;
y = temp;
Console.WriteLine(#34;x = {x},y = {y}");
}
static void Main(string[] args)
{
int myInt01 = 10;
int myInt02 = 20;
Console.WriteLine(#34;值类型作为引用参数前:myInt01={myInt01},myInt02={myInt02}");
Swap(ref myInt01, ref myInt02);
Console.WriteLine(#34;值类型作为引用参数后:myInt01={myInt01},myInt02={myInt02}");
Console.ReadLine();
}
}
}
控制台输出:
值类型作为引用参数前:myInt01=10,myInt02=20
x = 10,y = 20
x = 20,y = 10
值类型作为引用参数后:myInt01=20,myInt02=10
说明:
1. 在5.2中,值参数无法实现将值类型的实参变量a和b通过方法实现交换,而此处引用参数可以实现值类型的实参变量a和b通过方法实现交换。
2. 注意区分值参数的值类型变量,实参给形参传递的是实参值复制的值。而引用参数的值类型变量,实参给形参传递的是引用,此时形参是实参的别名,它们都指向内存中相同的位置。
6. 引用类型作为值参数和引用参数
- 对于一个引用类型对象,不管是将其作为值参数传递还是引用参数传递,都可以在方法成员内部修改这个引用类型对象的成员。
6.1 将引用类型对象作为值参数传递
- 如果在方法内创建一个新对象并赋值给形参,将切断形参与实参的关联,并在方法调用结束之后,这个在方法内创建的对象将不复存在。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo01
{
class MyClass
{
public int Var = 20;
}
class Program
{
static void RefAsParameter(MyClass f1)
{
f1.Var = 50;
Console.WriteLine(#34;After member assignment:{f1.Var}");
f1 = new MyClass();
Console.WriteLine(#34;After new object creation:{f1.Var}");
}
static void Main(string[] args)
{
MyClass a1 = new MyClass();
Console.WriteLine(#34;Before method call:{a1.Var}");
RefAsParameter(a1);
Console.WriteLine(#34;After method call:{a1.Var}");
Console.ReadLine();
}
}
}
控制台输出:
Before method call:20
After member assignment:50
After new object creation:20
After method call:50
说明:
1. 在方法开始时,形参和实参指向堆中相同的对象。在方法体中为对象的成员赋值后,它们任然指向堆中相同的对象。
2. 当方法分配新的对象并赋值给形参时,(方法外部的)实参任然指向原始对象,而形参指向的是新的对象。
3. 在方法调用后,实参继续指向原始对象,形参和新对象两者都会消失。
6.2 将引用类型对象作为引用参数传递
- 如果在方法内部创建一个新对象并赋值给形参,在方法结束后这个在方法内创建的对象依然存在,并且是实参所引用的值。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo01
{
class MyClass
{
public int Var = 20;
}
class Program
{
static void RefAsParameter(ref MyClass f1)
{
f1.Var = 50;
Console.WriteLine(#34;After member assignment:{f1.Var}");
f1 = new MyClass();
Console.WriteLine(#34;After new object creation:{f1.Var}");
}
static void Main(string[] args)
{
MyClass a1 = new MyClass();
Console.WriteLine(#34;Before method call:{a1.Var}");
RefAsParameter(ref a1);
Console.WriteLine(#34;After method call:{a1.Var}");
Console.ReadLine();
}
}
}
控制台输出:
Before method call:20
After member assignment:50
After new object creation:20
After method call:20
说明:
1. 当方法调用时,形参和实参指向堆中相同的对象。
2. 方法体中对成员值的修改会同时影响到实参和形参。
3. 当方法创建新的对象并赋值给形参时,形参和实参的引用都指向该新的对象。
4. 在方法结束之后,实参指向在方法内创建的新对象。
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
总结:使用ref修饰符的引用参数,形参是实参的别名,它们指向同一个内存位置。也可以理解为ref修饰符是将形参和实参进行了某种“绑定”,但是形参在方法结束后消失,实参在对应的代码块当中有效。※这个表述可能不准确※
7. 输出参数
- 输出参数用于从方法体内把数据传出到调用代码,它的行为与引用参数类似。输出参数有以下要求:
- 必须在声明和调用中都使用修饰out
- 和引用参数相似,实参必须是变量,而不能使表达式。
void MyFunc(out int val) // 方法声明
{
...
}
int y = 1; // 实参变量
MyFunc(out y) // 方法调用
- 和引用参数不同,输出参数有如下要求
- 在方法内部,给输出参数赋值之后才能读取它。因此,输出参数的形参与初始值无关,只有在方法体内给形参赋值之后才能使用。
- 在方法体内部,在方法返回之前,必须给所有输出参数赋值。
- 对于输出参数,形参好像是实参的别名,但还有一个要求就是必须在方法内给所有的形参赋值。
class MyClass
{
public int Var = 20;
}
class Program
{
static void MyFunc(out MyClass f1, out int f2)
{
f1 = new MyClass();
f1.Var = 25;
f2 = 15;
}
static void Main()
{
MyClass a1 = null; // 声明被用作out参数的变量,引用类型的实参可以为空
int a2; // 声明被用作out参数的变量,实参可以不被初始化
MyFunc(out a1, out a2); // 调用方法
}
}
说明:
1. 在方法调用之前,将要被用作实参的a1和a2已经在栈里面了。
2. 在方法开始调用处,形参的名称被设置为实参的别名。即变量a1和形参f1指向的是内存同一个位置,同样a2和f2指向的也是内存同一个位置。
3. a1和a2不在MyFunc方法的作用域内,因此不能在MyFunc方法内直接访问。
4. 在MyFunc方法体内部,创建了一个MyClass类型的对象并赋值给形参f1,然后给f1的字段赋值为25,给形参f2赋值为15。
5. 输出参数必须给所有形参赋值。
6. 方法执行完成之后,形参的名称失效,但是引用类型的a1和值类型的a2的值都被方法内部的行为改变了。
注意事项:方法中在给输出参数赋值之前读取它的值,编译器会产生一条错误信息。
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 从C# 7.0开始,不再需要预先声明一个变量来用作输出参数的实参了。可以在调用方法的时候在参数列表中添加变量类型,它将作为实参变量的声明。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo01
{
class MyClass
{
public int Var = 20;
}
class Program
{
static void MyFunc(out MyClass f1, out int f2)
{
f1 = new MyClass();
f1.Var = 25;
f2 = 15;
}
static void Main()
{
MyFunc(out MyClass a1, out int a2); // 方法调用时参数列表中添加变量类型。
a2 += 5;
Console.WriteLine(a1.Var); // a1在调用时声明,在方法调用完成之后可以继续使用。
Console.WriteLine(a2); // a2在调用时声明,在方法调用完成之后可以继续使用。
Console.ReadLine();
}
}
}
控制台输出:
25
20
说明:
1. 使用新的语法,可以消除显式的out参数变量的声明。
2. 直接在方法调用时加入变量类型声明。
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
总结:
1. ref要求变量必须在传递之前进行初始化,out则不需要在传递之前进行初始化。
2. out要求在方法返回到调用处之前将所有输出参数进行赋值。
8. 参数数组
- 数组参数允许特定的零个或多个实参对应一个特定的形参,参数数组的重点如下。
- 一个参数列表中只能有一个参数数组。
- 一个参数列表如果有参数数组,该参数数组必须是参数列表中最后一个。
- 由参数列表组成的所有参数必须是同一类型的。
- 声明一个参数数组时必须做的事情如下。
- 在数据类型前使用params修饰符。
- 在数据类型后放置一组空的符号。
void ListInts(params int[] inVals)
↑ ↑ ↑
修饰符 int型参数数组 参数名称
说明:类型名后面的方括号指明了参数是一个整形数组,数组是一个引用类型,它的所有数据项都保存在堆中。
8.1 含参数数组的方法调用形式
- 有两种方式为参数数组提供实参
// 方式1:一个用逗号分隔的该数据类型元素的列表,这种调用形式有时候称为延伸式。
ListInts(10, 20, 30); // 所有元素必须是方法声明中指定的类型。
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 方式2:一个该数据类型元素的一维数组。
int[] myList = {1, 2, 3, 4, 5}; // 声明并初始化数组变量。
ListInts(myList); // 一个数组变量
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
总结:上述两种方式,没有在调用时使用params修饰符。
8.2 参数数组中修饰符的使用
- 除参数数组之外我们学习的其它参数类型,要么都使用修饰符,要么都不使用修饰符。
- 值参数的声明和调用都不带修饰符。
- 引用参数和输出参数在声明时和调用时都必须带上修饰符ref或out。
- params在声明时需要修饰符,在调用时不允许有修饰符。
8.3 延伸式调用形式示例
// 声明方法
void ListInts(params int[] inVals)
{
...
}
// 调用方法
ListInts(); // 0个实参
ListInts(1, 2, 3); // 三个实参
ListInts(1, 2, 3, 5, 10); // 五个实参
说明:
1. 在使用一个为参数数组使用独立实参调用时,编译器首先接受实参列表,用它们在堆中创建并初始化一个数组。
1.1 例如ListInts()会在堆中创建一个数组{},该数组有0个元素。
1.2 ListInts(1, 2, 3)会在堆中创建一个数组{1, 2, 3},该数组有3个元素。
2. 把数组的引用保存在栈中的形参里,或者说形参接受了在堆中创建的数组的引用。
3. 如果在对应形参数组的位置没有实参,编译器会创建一个有0个元素的数组来使用。
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo01
{
class MyClass
{
public void ListInts(params int[] inVals)
{
if((inVals != null) && inVals.Length != 0)
{
for(int i = 0; i < inVals.Length; i++)
{
inVals[i] = inVals[i] * 10;
Console.WriteLine(#34;{inVals[i]}");
}
}
}
}
class Program
{
static void Main()
{
int firstInt = 5, secondInt = 6, thirdInt = 7;
MyClass myClass = new MyClass();
myClass.ListInts(firstInt, secondInt, thirdInt); // firstInt,secondInt,thirdInt表示3个实参。
Console.WriteLine(#34;{firstInt}, {secondInt}, {thirdInt}");
Console.ReadLine();
}
}
}
控制台输出:
50
60
70
5, 6, 7
说明:
1. 在方法调用前firstInt、secondInt、thirdInt这3个实参已经在栈里。
2. 在方法开始调用时firstInt、secondInt、thirdInt这3个实参会首先被用于初始化堆中的数组,这个数组的引用被赋值给形参inVals。
2.1 注意实参的值复制一份组成数组的元素,而不是将实参本身作为数组的元素。
2.2 堆中的数组是{5, 6, 7},而不是{firstInt, secondInt, thirdInt},可以理解为值参数。
2.3 如果数组参数是值类型,那么值被复制,实参在方法内不受影响;如果数组参数是引用类型,那么引用被复制,实参引用的对象在方法内会受到影响。
3. 在方法内部,首先检查数组是否为null,数组元素的个数是否为0。然后处理数组,把数组的每个元素乘以10。
4. 方法执行完之后,形参intVals失效。
8.4 将数组作为实参调用形式示例
// 在方法调用之前先声明一个数组变量并完成初始化,然后把这个数组变量作为实参传递,这时候编译器会直接使用事先声明的数组变量,而不在创建新的数组。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo01
{
class MyClass
{
public void ListInts(params int[] inVals)
{
if((inVals != null) && inVals.Length != 0)
{
for(int i = 0; i < inVals.Length; i++)
{
inVals[i] = inVals[i] * 10;
Console.WriteLine(#34;{inVals[i]}");
}
}
}
}
class Program
{
static void Main()
{
int[] myArr = new int[] { 5, 6, 7 };
MyClass myClass = new MyClass();
myClass.ListInts(myArr);
foreach (int x in myArr)
Console.WriteLine(x);
Console.ReadLine();
}
}
}
控制台输出:
50
60
70
50
60
70
说明:将数组变量作为实参,在方法调用时,编译器并不会再创建一个新的数组。此时形参是数组变量的别名,形参和实参指向的是同一个数组。
9. 参数类型总结
10. ref局部变量和ref返回
10.1 ref局部变量
- ref局部变量 → 它允许一个变量是另一个变量的别名,ref局部变量的说明如下。
- 可以使用ref局部变量创建一个变量的别名,即使引用的对象是值类型。
- 对任意一个变量的赋值,都会反映到另一个变量上,因为它们引用的是同一个对象,即使是值类型。
// 给局部变量创建别名的语法
ref int y = ref x;
说明:创建别名需要使用关键字ref两次,一次是在别名声明在类型的前面。另一次是在赋值运算符的右边,“被别名”的变量前面。
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo01
{
class Program
{
static void Main()
{
int x = 2;
ref int y = ref x;
Console.WriteLine(#34;x={x}, y={y}");
x = 5;
Console.WriteLine(#34;x={x}, y={y}");
y = 10;
Console.WriteLine(#34;x={x}, y={y}");
Console.ReadLine();
}
}
}
控制台输出:
x=2, y=2
x=5, y=5
x=10, y=10
说明:别名功能并不是局部变量ref的常见用途,别名功能经常和ref返回功能一起使用。
10.2 ref返回
- ref返回功能提供了一种使方法返回变量引用而不是变量值的方法,这种功能也需要使用ref关键字两次。
- 一次是在方法返回类型声明之前。
- 一次是在return关键字之后,被返回对象的变量名之前。
// 作用1:在方法作用域外修改值,会在方法内部体现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo01
{
class MyClass
{
private int Score = 5;
public ref int RefToValue()
{
return ref Score;
}
public void Display()
{
Console.WriteLine(#34;MyClass类中字段的值为{Score}");
}
}
class Program
{
static void Main()
{
MyClass myClass = new MyClass();
myClass.Display();
ref int outSide = ref myClass.RefToValue();
outSide = 10; // 在方法调用外面修改值
myClass.Display();
Console.ReadLine();
}
}
}
控制台输出:
MyClass类中字段的值为5
MyClass类中字段的值为10
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 作用2:提供两个数字类型变量,Math.Max能够返回两个值中较大一个,此时返回的是实际的值。如果想返回较大值的引用,而不是实际的值可以用ref来实现。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo01
{
class Program
{
static ref int Max(ref int myInt01, ref int myInt02)
{
if (myInt01 > myInt02)
return ref myInt01;
else
return ref myInt02;
}
static void Main()
{
int val01 = 10;
int val02 = 20;
Console.WriteLine(#34;起始时val01:{val01}, val02:{val02}");
ref int maxNum = ref Max(ref val01, ref val02);
Console.WriteLine(#34;经过比较后,较大的数是{maxNum}");
maxNum++;
Console.WriteLine(#34;自增之后,maxNum:{maxNum},val01:{val01}, val02:{val02}");
Console.ReadLine();
}
}
}
控制台输出:
起始时val01:10, val02:20
经过比较后,较大的数是20
自增之后,maxNum:21,val01:10, val02:21
注意事项:
1. 不能将返回值类型是void的方法声明为ref返回方法。
2. ref retuan表达式不能返回空值、常量、枚举成员、类或者结构体的属性、指向只读位置的指针。
3. ref retuan表达式只能指向原先就在调用域内的位置,或者字段。ref return表达式不能指向方法的局部变量。
4. ref局部变量只能被赋值一次,也就是说ref局部变量一旦初始化,他就不能指向不同的存储位置了。
5. 如果将一个方法声明为ref返回方法,如果在调用方法时省略了ref关键字,则返回的是值本身,而不是指向值的内存位置的指针。
6. 如果将ref局部变量作为常规的实际参数传递给其它方法,则该方法仅获取该变量的一个副本。尽管ref局部变量包含指向存储位置的指针,但是当以这种方式调用时,它传递的是值而不是引用。
结尾
书籍:C#图解教程
著:【美】丹尼尔 · 索利斯;卡尔 · 施罗坦博尔
译:窦衍森;姚琪琳
ISBN:978-7-115-51918-4
版次:第5版
发行:人民邮电出版社
※敬请购买正版书籍,侵删请联系85863947@qq.com※
※本文章为看书或查阅资料而总结的笔记,仅供参考,如有错误请留言指正,谢谢!※
相关推荐
- 信奥赛知识点_信奥赛 教材
-
信息学奥赛(NOIP/CSP等)中,C语言是核心编程语言,考察重点是算法逻辑、数据结构应用和代码效率。以下整理了信奥赛中典型的C语言知识点及对应试题(从基础到进阶),涵盖入门到提高组常见内容。...
- 如何在 Docker 中设置环境变量 ?_docker run设置环境变量
-
Docker是一个开源平台,它简化了在容器中创建、部署和管理应用程序。一个容器是一种可移植的、轻量级的、自包含的运行时环境,包含运行应用程序所需的一切。容器化的关键组成部分之一是管理环境变量。环境变...
- C++中的头文件以及源文件_c++头文件格式有哪些
-
在C++中,头文件和源文件是组织代码的两种不同文件,作用和编写方式不同,是组织代码的基本方式,两者共同构成了项目的模块化结构头文件的作用头文件扩展名为`.h`或`.hpp`,通常包含:函数声明(原型)...
- 杰x分享(102):51单片机基础(二十四)
-
分享兴趣,传播快乐,增长见闻,留下美好。亲爱的您,这里是LearingYard学苑!今天小编为您带来“51单片机基础”欢迎您的访问!Shareinterest,spreadhappiness,i...
- 西门子S71200/1500PLC用GET_DIAG指令获取第三方IO模块通信状态?
-
我们在项目中,如果是西门子PLC的分布式IO模块,可以通过调用DeviceStates指令或者ModuleStates指令来获取模块的详细信息。下图是采用DeviceStates指令来获取两个IO...
- Python变量类型和运算符_python中变量类型
-
变量类型变量与命名规则在Python中,变量是存储数据的容器,不需要事先声明类型,直接赋值即可创建。变量名只能包含字母、数字和下划线,且不能以数字开头。Python的变量名是大小写敏感的(例如a...
- 02010602 方法02-值参数、引用参数、输出参数、参数数组
-
02010602方法02-值参数、引用参数、输出参数、参数数组、ref局部变量和ref返回方法的参数是一个特殊变量1.形参形参→是局部变量,它声明在方法的参数列表中,而不是方法体中。publi...
- C/C++语言的const关键字说明_c++ const详解
-
在C/C++编程领域,const关键字是一个基础且关键的存在。它如同“安全卫士”,能帮助开发者限制数据的修改,减少程序中的bug,提升代码的可读性和可维护性。无论是刚接触C/C++的初学者,还是有一定...
- JavaScript ES6 let、cont、解构_js es6方法
-
let和const遇到{}就形成作用域同一作用域不能重复声明变量或函数[如:let声明过不能用const和var声明相同名字]没有变量提升const必须初始化赋值,不能被修改,而...
- Kubernetes v1.34: 使用 Init 容器定义应用环境变量
-
Kubernetes通常使用ConfigMap和Secret来设置环境变量,这会引入额外的API调用和复杂性。例如,你需要分别管理工作负载的Pod和它们的配置,同时还要确保配置和...
- 全面详解 Python 类变量与实例变量的访问步骤
-
1.核心概念:什么是类变量和实例变量?在开始讨论访问步骤之前,我们首先要明确这两个概念的定义和区别。类变量(ClassVariable)定义位置:在类的内部,但在任何方法(包括__init__...
- golang编程细讲-变量/常量/表达式
-
我们之前说到了函数通常封装了单个事情的处理过程。这个处理的过程通常需要有输入信息,然后处理后,产生/返回处理结果信息。这些输入/输出的信息,或者说数据,我们使用变量来表示。因此变量这个概念本身就是一种...
- Python 访问类变量与实例变量:步骤梳理与原理讲解
-
核心概念速览在深入细节之前,我们先快速区分一下两者:类变量(ClassVariable):定义位置:在类的内部,但在任何方法的外部。所属对象:属于类本身。共享性:被所有该类的实例(对象)共享...
- golang嵌入脚本语言-tengo语言的语法-变量/语句/表达式
-
让我们步入tengo的基本语法部分。首先tengo支持单行注释和多行注释://这是一个单行注释/**这是一个多行注释*/其次,tengo是一个动态脚本语言,因此变量本身无类型,有类型的是变量...
- 【第17集】C++ 逻辑变量:编程世界的"真假侦探"
-
同学们好!今天我们要学习C++中超级重要的逻辑变量!它们就像是编程世界的"真假侦探",专门负责判断条件是真还是假!一、什么是逻辑变量?通俗理解:逻辑变量=编程版的"是非题...
- 一周热门
- 最近发表
-
- 信奥赛知识点_信奥赛 教材
- 如何在 Docker 中设置环境变量 ?_docker run设置环境变量
- C++中的头文件以及源文件_c++头文件格式有哪些
- 杰x分享(102):51单片机基础(二十四)
- 西门子S71200/1500PLC用GET_DIAG指令获取第三方IO模块通信状态?
- Python变量类型和运算符_python中变量类型
- 02010602 方法02-值参数、引用参数、输出参数、参数数组
- C/C++语言的const关键字说明_c++ const详解
- JavaScript ES6 let、cont、解构_js es6方法
- Kubernetes v1.34: 使用 Init 容器定义应用环境变量
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- opacity 属性 (32)
- transition 属性 (33)
- 1-1. 变量声明 (31)