paramsrefin out 方法参数
申明方法参数时可以使用的关键字:
params:指定该参数采用可变数量的参数。
in:指定此参数由引用调用,但是只由调用方法读取。
ref:指定该参数为引用传递,可能由调用方法读取或写入。
out:指定此参数为引用传递,由调用方法写入。
1. params:
使用params关键字可以指定采用数目可变的参数
可以发送参数申明中指定类型的逗号分隔的参数列表或者指定类型的参数数组,也可以不发送参数,那样参数列表长度为0
限制:在方法申明params关键字之后不允许有任何其它参数,一个方法只能由一个params参数, 申明的params参数类型必须是一维数组
FuncTestParams("fasdf", 123, 0.111f);
var t = new object[]{"fasdf", 123, 0.111f};
FuncTestParams(t);
public void FuncTestParams(params object[] list)
{
for (int i = 0; i < list.Length; i++)
{
Debug.Log(list[i].ToString());
}
}
2. in:
in关键字通过引用传递参数。它让形参成为实参的别名,这必须是变量。对形参执行的任何操作都是对实参执行的,in参数无法通过调用的参数进行修改。
void InArgExample(in int number)
{
// Uncomment the following line to see error CS8331
//number = 19;
}
重载决策规则:
定义使用in参数的方法是一项潜在的性能优化,某些struct类型参数可能很大,在紧凑循环或者关键代码中, 复制的成本比较高。
在函数调用的地方申明in是可选的,按值传递和使用in按引用传递并没有语义差异。显式使用in能强制编译器选择使用in
参数定义的方法,不然如果两种方法都存在,按值重载的匹配度会更高。
3. ref:
在方法的参数列表中使用Ref关键字时,它指示参数按引用传递,而非按值传递。ref关键字让形参成为实参的别名,这必须是变量。
按引用传递参数
//Demo1
var num = 1;
FuncRef(ref num);
Debug.Log(num); // 2
public void FuncRef(ref int num)
{
num = 2;
}
//Demo2
Test t = null;
FuncRef(ref t);
Debug.Log(t?.Num); // 10 哪怕传进去的值为null,依然可以在函数内修改
public void FuncRef(ref Test k)
{
k = new Test(10);
}
public class Test
{
public int Num;
public Test(int val) { Num = val; }
}
ref返回值和ref局部变量
ref var res = ref FuncRef();
res = new Test(10);
Debug.Log(list[0]?.Num); //10
Test[] list = new Test[3]{new Test(1), new Test(2), new Test(3)};
public ref Test FuncRef()
{
return ref list[0];
}
4. out:
out和ref的作用相似,只是ref使用在函数调用前需要初始化,而out不需要初始化但是需要在函数内进行赋值。
5. 总述:
四种类型传递:
值按值传递:
形参是实参的拷贝,函数对形参进行修改不会影响到实参。
引用按值传递:
形参和实参指向同一块内存,如果只是修改形参内容,实参的内容也会被修改,但是如果将形参指向另一块内存,那么实参和形参就没有关系了。
值按引用传递:
形参是实参的别名,修改形参会影响实参。
引用按引用传递:
形参是实参的别名,修改形参会影响实参。包括修改内容和将形参指向另一块内存。
in, out, ref 修饰符都能让参数按引用进行传递。
限制
不能将 in、ref 和 out 关键字用于以下几种方法:
异步方法,通过使用 async 修饰符定义。
迭代器方法,包括 yield return 或 yield break 语句。
扩展方法的第一个参数不能有 in 修饰符,除非该参数是结构。
扩展方法的第一个参数,其中该参数是泛型类型(即使该类型被约束为结构。)