【⼜长见识了】函数传参,params参数,ref和out参数详解
 ⼀、原来函数这样传参
  先看⼀个函数和函数调⽤。 
static void Main(string[] args)
{
int num = 10;
Test(num);//局部变量在使⽤之前赋值
//Test(10); //直接为局部变量赋值
}
static void Test(int i)//i 相当于⼀个局部变量
{
i++;
}
  Test函数定义了⼀个int 类型的变量i作为参数,这个地⽅相当于声明了⼀个局部变量,⽽局部变量使⽤之前必须赋值,这就是为什么函数使⽤的时候要赋值(传⼀个值进去)。
  假如不想给参数赋值怎么办?那就在函数声明参数的时候给参数(局部变量)赋值,这样调⽤函数的时候就可以不给参数传值。如下:
static void Main(string[] args)
{
int x=  Test();//可以不传值
int y= Test(20);//也可以传值
Console.WriteLine(x);
Console.WriteLine(y);
Console.Read();
}
static int Test(int i=10)//为局部变量赋值,传参数的时候可以不为i赋值
{
i++;
return i;
}
  注意:赋初值的参数必须放在参数列表最右侧,可以有多个带初值的参数。
  作⽤:为参数赋了初值,在调⽤的时候可以赋值也可以不赋值,作⽤是为参数指定默认值,。
static void  Test(int a,int b=20, int i=10)
{
/
/to do
}writeline输出数值变量
  在为⽅法传参数的时候必须按照参数声明的顺序传,这个⼀直是这样做的,也没多想过,其实也可以不按照传参的顺序,如下:
static void Main(string[] args)
{
Test2(s:"hello",b:true ,i:10);      //请看这个地⽅
Console.Read();
}
static void  Test2(int i,string s,bool b)
{
Console.WriteLine(i);
Console.WriteLine(s);
Console.WriteLine(b);
}
  传参的时候指定哪个参数传什么值就可以不按照顺序传参,这个不是很常⽤,但是以前不知道,⼜长见识了。
补充:评论你有⼈问,如果有重载怎么办,这个问题,问得⾮常好。先看⼀下下⾯的代码
static void Main(string[] args)
{
int x = Test(10);
int y = Test(20,30);
int z = Test(10, 20, 30);
Console.WriteLine(x);//输出10
Console.WriteLine(y);//输出50
Console.WriteLine(z);//输出60
Console.Read();
}
static int Test(int i )
{
return i;
}
static int Test(int a,int b=20)
{
return a + b;
}
static int Test(int a,int b=20,int c=30)
{
return a + b + c;
}
  当有重载的时候,不给带有默认值参数赋值,他会优先执⾏,不带默认参数的函数。
⼆、params 参数数组(可变参数)
  我们知道数组的长度是不可变的。当我们把⼀个数组作为参数传递的时候,想改变数组长度不是⼀件容易的事⼉。params 参数数组就可以随便指定参数长度,也不⽤在传参的时候去特意定义⼀个数组传参。使⽤⾮常⽅便。
  例:
static void Main(string[] args)
{
int[] arr = new int[]{1,2,4,5,6};
Test1(arr);
Console.WriteLine();
Test2(1,2,4,56,78,8,4);
Console.WriteLine();
Test2(1,5,7);
Console.Read();
}
static void Test1(int [] arr )
{
for (int i = 0; i < arr .Length ; i++)
{
Console.Write(arr [i]+"");
}
}
static void  Test2(params int[] arr)              //params 数组
{
for (int i = 0; i < arr.Length; i++)
{
Console.Write(arr [i]+"");
}
}
  params 参数数组,作为参数的时候,参数个数是可变的,当然也可以为0,但是⽤params 参数数组的时候,⼀个函数⾥只有⼀个params参数,并且必须放在参数列表的最后。
  params⽤法: 1、⽤来修饰⽅法的参数,⽽且只能修饰⼀维数组;
          2、⼀个⽅法只能出现⼀个params参数,并且必须把params参数数组放在最后,不能带有默认值;
          3、调⽤⽅法的时候,params修饰的参数,可以传⼀个数组,也可以传数组的元素,也可以什么都不传(长度就为0);
  在控制台应⽤程序中,如Console.WriteLine("我叫{0},今年{1}岁,喜欢{2}","Vivu","22","C#");其实就⽤到了params参数,这个重载就是:
  console.WriteLine(string.Format,Params string[] arr);         
  总结:params 参数修饰的数组相当于长度可变的参数数组。它是修饰参数(⼀维数组)的⼀个关键字。⽤处就是在不知道参数个数或参数个数有可能发⽣变化的情况下使⽤。
三、ref和out参数修饰符
ref: 
  值类型在传递值的时候,只是复制了⼀份值赋给另⼀个变量,另⼀个变量改变并不能改变原有的值。例如: 
int num = 200;
int a = num;
a -= 100;
Console.WriteLine(num);//输出200
Console.WriteLine(a);//输出100
  但是,假如num代表我钱包⾥的钱,我把钱包交给别⼈(int a=num),别⼈⽤了100(a-=100),这时候,我钱包⾥的钱(num)应该是多少?按照上⾯的⽅式执⾏就会出错,钱包⾥的钱是不会变的,因为在传值的时候只是复制了num的⼀份值给a,a改变并不会改变num的值。那该怎么办
  如果我传递的值是num的引⽤(可以理解为地址),那么a 改变了num就也会改变了。但是int 类型是值传递,怎么办,把它变为引⽤就要⽤到ref和out参数。
  ref和out参数的作⽤就是把值传递改为引⽤传递。
  改写上⾯的钱包的例⼦。
static void Main(string[] args)
{
int num = 200;
int res =Test(ref num );
Console.WriteLine(num );//输出100
Console.WriteLine(res );//输出100
Console.Read();
}
static int Test(ref int a)
{
a -= 100;
return a;
}
  在内存图中分析⼀下ref参数:
  ref参数可以按引⽤类型传递,如果ref修饰的是引⽤类型的参数呢?先看下⾯的例⼦:
  先创建⼀个person类 
private int _age;
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
public int Age
{
get { return _age; }
set { _age = value; }
}
Person类
  再看⼀下⾯ref修饰引⽤类型的情况。
static void Main(string[] args)
{
Person p = new Person() { Name ="红红"};
Test1(p);
Console.WriteLine(p.Name); //输出什么
TestRef1(ref p);
Console.WriteLine(p.Name);  //输出什么
Test2(p);
Console.WriteLine(p.Name); //输出什么
TestRef2(ref p);
Console.WriteLine(p.Name);  //输出什么
Console.Read();
}
static void Test1(Person p)
{
p = new Person() { Name = "绿绿" };
}
static void TestRef1(ref Person p)
{
p = new Person() { Name ="蓝蓝"};
}
static void Test2(Person p)
{
p.Name = "嘿嘿";
}
static void TestRef2(ref Person p)
{
p.Name = "掰掰";
}
  输出结果是,红红,蓝蓝,嘿嘿,掰掰。画⼀下内存图很好分析。引⽤类型本来传递的就是地址,所以引⽤类型使⽤ref参数和不使⽤是⼀样的。这⾥偷⼀下懒,想知道的去运⾏,画⼀下内存图吧
  ref⽤法:1、使⽤ref必须在参数声明和调⽤的时候都带上ref关键字;
       2、只能修饰变量,不能修饰常量;
       3、ref在⽅法中可以对ref修饰的值不改变,但是在传参前必须给参数赋值;
out:
  ref 在使⽤之前必须赋初始值,它主要侧重于改变,修改值。使⽤ref,在函数声明与调⽤的时候必须在参数前⾯加上ref。out参数的作⽤与使⽤⽅法与ref类似,与ref不同的是out在使⽤前不必赋初始值,但在返回的时候必须为他赋值,所以out主要侧重于输出。out修饰符参数例⼦:
static void Main(string[] args)
{
int num = 200;
int b;
int a = TestOut(200,out b);
Console.WriteLine(a);//输出100
Console.WriteLine(b);//输出200
Console.Read();
}
static int TestOut(int a,out int b)
{
b = a;
a -= 100;
return a;
}
总结:ref和out参数修饰符,都是把参数按引⽤类型传递,但是ref侧重于改变值,⽽out侧重于输出。⼀个函数只有⼀个输出值,但想返回多个值的时候就⽤out参数修饰符。
      ref在使⽤之前必须赋值,out在返回之前必须赋值。ref和out在函数使⽤和调⽤的时候,参数前⾯必须加ref和out参数。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。