先把最重要的一句话放在前面:通常向方法传递一个实参时,对应的参数(形参)会用实参的一个副本来初始化。
1、(引用传递)首先是传递引用类型的参数:
-
当我们将类型A定义为class类型时,则创建了一个引用类型。
-
在main()函数中进行实例化后,调用ChangeA函数对A中的X进行修改,所得结果为:
a1的值为:2
,我们发现,调用ChangeA函数改变了a1的X值 -
原因:调用函数ChangA传递参数a1,是传递的保存在栈中的内存地址,当改变X的值时改变的时堆中的值。堆中的值改变之后,所有的引用该地址的值都会发生改变,则会残生这种现象。
2、(值传递)其次是传递值类型的参数
- 当我们将Class A改为Struct A时,A类型则变成了值类型
- 在Main()函数中调用ChangeA进行改变A类型的X值,结果我们发现,X的值还是1:
a1的值为:1
,并没有改变。 - 原因:在给函数传递参数时,会对实参赋值一个副本,导致函数改变的X值时存放在栈中的副本值,当我们打印a1.X值时栈中的值是没有改变的。
using System;
namespace test
{
class Program
{
static void Main(string[] args)
{
var a1 = new A() { X = 1 };
ChangeA(a1);
Console.WriteLine($"a1的值为:{a1.X}");
Console.ReadKey();
}
public static void ChangeA(A a)
{
a.X = 2;
}
}
struct A
{
public int X { get; set; }
}
}
3、(ref)如果我们想要在Struct中传递引用类型的值进行对值改变,我们怎么做呢?
- 那就是使用我们ref关键字,对在函数中传递的实参进行
- 需要改变的地方有两个:一个时函数声明时,在形参前加上ref关键字,另一个是在调用的时候也需要加上ref关键字。
- ref关键字在实战中什么时候用的到欢迎评论(Thx)
using System;
namespace test
{
class Program
{
static void Main(string[] args)
{
var a1 = new A() { X = 1 };
ChangeA(ref a1);
Console.WriteLine($"a1.X的值为:{a1.X}");
Console.ReadKey();
}
public static void ChangeA(ref A a)
{
a.X = 2;
}
}
struct A
{
public int X { get; set; }
}
}
4、对引用的应用,类型于和C++的指针类似
- 当我们使用ref关键字时,就会在函数调用时对实参创建一个引用,放在堆中,然后在函数中对堆中的数据进行处理
- 如果我们在函数中对被创建的引用类型的参数进行操作的话,就相当于对C中的指针内容进行操作
- 最后Main()函数输出的结果为
a1.X的值为:3
public static void ChangeA(ref A a)
{
a.X = 2;
a = new A { X = 3 };
}
5、(out)如果我们想要从一个方法中返回一个数或者多个数据,并且这些数据的类型可能不同,那么我们有三种办法处理
- 使用函数返回类型
- 声明一个类或者结构用做返回类型
- 使用out关键字,用于参数,将要返回的数据带出来
- out关键字的使用会经常和Int.TryParse一起使用,Int.TryParse(int param1 ,out object param2)是用来判断param是否能转化为整数,如果能,则对param2进行赋值并返回。代码如下:
using System;
namespace test
{
class Program
{
static void Main(string[] args)
{
string input = Console.ReadLine();
if (int.TryParse(input,out int result))
{
Console.WriteLine($"result:{result}");
}
else
{
Console.WriteLine("not a number");
}
}
}
}
6、(in)如果我们想把一个参数传到方法内,并且保证该变量的值不被改变,我们可以使用in修饰符
- 声明带in的函数时,将in放在参数类型的前面
- 调用该函数时,使用或者不适用in都不会影响该函数的运行。
- 使用带in修饰符的值类型不仅有助于确保不能更改内存,而且编译器还可以创建更好的优化代码。编译器可以使用引用代替方法调用复制值类型,从而减少所需的内存并提高性能。
using System;
namespace test
{
class Program
{
static void Main(string[] args)
{
}
static void CantChange(in MyStruct myStruct)
{
myStruct.Data = 19;//编译出错, 该属性是只读的不能改变
}
}
struct MyStruct
{
public int Data { get; set; }
}
}