在C#中,方法的参数传递有四种类型:
传值(by value),
传址(by reference),
输出参数(by output),
数组参数(by array)。传值参数无需额外的修饰符,传址参数需要修饰符ref,输出参数需要修饰符out,数组参数需要修饰符params。传值参数在方法调用过程中如果改变了参数的值,那么传入方法的参数在方法调用完成以后并不因此而改变,而是保留原来传入时的值。传址参数恰恰相反,如果方法调用过程改变了参数的值,那么传入方法的参数在调用完成以后也随之改变。实际上从名称上我们可以清楚地看出两者的含义——
传值参数传递的是调用参数的一份拷贝,而传址参数传递的是调用参数的内存地址,该参数在方法内外指向的是同一个存储位置。
下面总结几种在项目中常用的参数传递:
1、常规值类型参数传递(如:整型参数传递)
Code
using System;
class Program
{
/// <summary>
/// 无引用参数
/// </summary>
/// <param name="m"></param>
/// <param name="n"></param>
static void ParamTest(int m, int n)
{
m = 1;
n = 2;
Console.WriteLine("now,m={0},n={1}", m, n);
}
/// <summary>
/// out参数
/// </summary>
/// <param name="m"></param>
/// <param name="n"></param>
static void OutTest(out int m, out int n)
{
//离开这个函数前,必须对m和n赋值,否则会报错。
//n = m;
//上面这行会报错,因为使用了out后,m和n都清空了,需要重新赋值,即使调用函数前赋过值也不行
m = 1;
n = 2;
}
/// <summary>
/// ref参数
/// </summary>
/// <param name="m"></param>
/// <param name="n"></param>
static void RefTest(ref int m, ref int n)
{
m = 1;
n = m;
}
public static void Main()
{
//值类型传递参数
int i = 22, j = 33;
ParamTest(i, j);
Console.WriteLine("still,i={0};j={1}", i, j);
//out test
int x, y;
//out使用前,变量可以不赋值
OutTest(out x, out y);
Console.WriteLine("here comes the out parameter:");
Console.WriteLine("x={0};y={1}", x, y);
int xx = 11, yy = 22;
OutTest(out xx, out yy);
Console.WriteLine("here comes the out parameter:");
Console.WriteLine("xx={0};yy={1}", xx, yy);
//ref test
int a, b;
//RefTest(ref a, ref b);
//上面这行会出错,ref使用前,变量必须赋值
int aa = 10, bb = 100;
RefTest(ref aa, ref bb);
Console.WriteLine("here comes the ref parameter:");
Console.WriteLine("aa={0};bb={1}", aa, bb);
}
}
2、结构参数传递
Code
using System;
public struct Student
{
public string name;
public Student(string name)
{
this.name = name;
}
}
class Program
{
/// <summary>
/// 无引用参数
/// </summary>
/// <param name="stu"></param>
static void ParamTest(Student stu)
{
stu.name = "jeffery zhao";
Console.WriteLine("now,the student's name is {0}",stu.name);
}
/// <summary>
/// out参数
/// </summary>
/// <param name="m"></param>
/// <param name="n"></param>
static void OutTest(out Student stu)
{
stu.name = "jeffery zhao";
}
/// <summary>
/// ref参数
/// </summary>
/// <param name="m"></param>
/// <param name="n"></param>
static void RefTest(ref Student stu)
{
stu.name = "jeffery zhao";
}
public static void Main()
{
//结构类型传递参数
Student stu = new Student("jeff wong");
ParamTest(stu);
Console.WriteLine("still,student's name:{0}", stu.name);
//out test
Student outStu;
//out使用前,变量可以不赋值
OutTest(out outStu);
Console.WriteLine("here comes the out parameter:");
Console.WriteLine("student's name:{0}", outStu.name);
Student outStu1 = new Student("jeff wong");
OutTest(out outStu1);
Console.WriteLine("here comes the out parameter:");
Console.WriteLine("student's name:{0}", outStu1.name);
//ref test
//Student refStu;
//RefTest(ref refStu);
//上面这行会出错,ref使用前,变量必须赋值
Student refStu1 = new Student("jeff wong");
RefTest(ref refStu1);
Console.WriteLine("here comes the ref parameter:");
Console.WriteLine("student's name:{0}", refStu1.name);
}
}
3、普通引用类型参数传递
Code
using System;
public class Student
{
public string name;
public Student(string name)
{
this.name = name;
}
}
class Program
{
static void ParamTest(Student stu)
{
Console.WriteLine("before modified,the student's name is {0}", stu.name);
stu.name = "jeffery zhao";
Console.WriteLine("now,the student's name is {0}",stu.name);
}
/// <summary>
/// out参数
/// </summary>
/// <param name="m"></param>
/// <param name="n"></param>
static void OutTest(out Student stu)
{
stu = new Student(""); //必须初始化,否则编译错误
stu.name = "jeffery zhao";
}
/// <summary>
/// ref参数
/// </summary>
/// <param name="m"></param>
/// <param name="n"></param>
static void RefTest(ref Student stu)
{
stu.name = "jeffery zhao";
}
public static void Main()
{
//引用类型传递参数
Student stu = new Student("jeff wong");
ParamTest(stu);
Console.WriteLine("still,student's name:{0}", stu.name);
//out test
Student outStu = new Student("jeff wong");
//out使用前,变量可以不赋值
OutTest(out outStu);
Console.WriteLine("here comes the out parameter:");
Console.WriteLine("student's name:{0}", outStu.name);
//ref test
//Student refStu;
//RefTest(ref refStu);
//上面这行会出错,ref使用前,变量必须赋值
Student refStu1 = new Student("jeff wong");
RefTest(ref refStu1);
Console.WriteLine("here comes the ref parameter:");
Console.WriteLine("student's name:{0}", refStu1.name);
}
}
4、
string类型参数传递(****)
Code
using System;
class Program
{
/// <summary>
/// 无引用参数
/// </summary>
/// <param name="m"></param>
/// <param name="n"></param>
static void ParamTest(string m, string n)
{
m = "1";
n = "2";
Console.WriteLine("now,m={0},n={1}", m, n);
}
/// <summary>
/// out参数
/// </summary>
/// <param name="m"></param>
/// <param name="n"></param>
static void OutTest(out string m, out string n)
{
//离开这个函数前,必须对m和n赋值,否则会报错。
//n = m;
//上面这行会报错,因为使用了out后,m和n都清空了,需要重新赋值,即使调用函数前赋过值也不行
m = "1";
n = "2";
}
/// <summary>
/// ref参数
/// </summary>
/// <param name="m"></param>
/// <param name="n"></param>
static void RefTest(ref string m, ref string n)
{
m = "1";
n = m;
}
public static void Main()
{
//string类型传递参数
string i = "22", j = "33";
ParamTest(i, j);
Console.WriteLine("still,i={0};j={1}", i, j);
//out test
string x, y;
//out使用前,变量可以不赋值
OutTest(out x, out y);
Console.WriteLine("here comes the out parameter:");
Console.WriteLine("x={0};y={1}", x, y);
string xx = "11", yy = "22";
OutTest(out xx, out yy);
Console.WriteLine("here comes the out parameter:");
Console.WriteLine("xx={0};yy={1}", xx, yy);
//ref test
string a, b;
//RefTest(ref a, ref b);
//上面这行会出错,ref使用前,变量必须赋值
string aa = "10", bb = "100";
RefTest(ref aa, ref bb);
Console.WriteLine("here comes the ref parameter:");
Console.WriteLine("aa={0};bb={1}", aa, bb);
}
}
通过上面的代码,我们发现string类型参数传递返回的结果和常规值类型参数传递(如:整型参数传递)返回的结果一致,这里把string类型单独拿出来,是为了区别对待string这种特殊类型。本质上string是引用类型,但是在实际计算和处理的时候,它处处透漏出值类型的特征。关于string类型,网上有无数精彩的文章介绍,这里不再多说。
5、数组参数
params 关键字可以指定在参数数目可变处采用参数的方法参数。 在方法声明中的 params 关键字之后不允许任何其他参数,并且在方法声明中只允许一个 params 关键字。
Code
using System;
class Program
{
/// <summary>
/// params关键字可以指定在参数数目可变处采用参数的方法参数。 在方法声明中的params关键字之后
/// 不允许任何其他参数,并且在方法声明中只允许一个params关键字。
/// </summary>
/// <param name="intArr"></param>
public static void ParamsTest(params int[] intArr)
{
for (int i = 0; i < intArr.Length; i++)
Console.WriteLine(intArr[i]);
}
public static void Main()
{
Console.WriteLine("here comes the parameters:");
int[] intArr=new int[]{1,2,3};
ParamsTest(intArr);
Console.WriteLine("---------------------------");
int[] intsArr = new int[20];
for (int i = 0; i < intsArr.Length; i++)
{
intsArr[i] = i;
}
ParamsTest(intsArr);
}
}
6、最后,总结一下:
在C# 中,既可以通过值也可以通过引用传递参数。通过引用传递参数允许函数成员更改参数的值,并保持该更改。若要通过引用传递参数, 可使用ref或out关键字。ref和out这两个关键字都能够提供相似的功效,其作用也很像C中的指针变量。它们的区别是:
传递参数中,关键字ref和out的区别:
(1)、使用ref型参数时,传入的参数必须先被初始化。对out而言,必须在方法中对其完成初始化。
(2)、使用ref和out时,在方法的参数和执行方法时,都要加Ref或Out关键字,以满足匹配。
(3)、out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候。