C#中有两种类型,值类型,和引用类型。在内存中值类型是直接存储在内存的栈中的,引用类型在栈中存放一个地址,这个地址指向堆中的数据(引用类型的数据是存放在堆中的)
下面我们来看看两种类型参数传递有什么区别
先看一个例子
/// <summary>///
/// 值类型的参数传递
/// </summary>
class ValueParms
{
public void Add(int a)
{
Console.WriteLine("Add:"+a);
}
public void Add1(ref int a)
{
a = a + 5;
Console.WriteLine("Add1:"+a);
}
public void Add2(out int a)
{
a = 10;
Console.WriteLine("Add2:"+a);
}
}
class Program
{
static void Main(string[] args)
{
int a=10;
ValueParms valueParms = new ValueParms();
/*@1*/ valueParms.Add(5); //5
/*@2*/ Console.WriteLine("Main" + a);//10
/*@3*/ valueParms.Add1(ref a);//15
/*@4*/ Console.WriteLine("Main" + a);//15
/*@5*/ valueParms.Add2(out a); //10
/*@6*/ Console.WriteLine("Main" + a);//15
}
我们来看一下输出的结果,第一行输出为5,Main 方法里面的a= 10不会随着方法的结果而改变
第三行输出为15 ,第四行为什么也是15呢,是因为ref这个参数(实际是把a的地址给传进来了),会把方法里得到的结果(a=15)带给Main方法里的属性(实参)
第五行 参数out的意思是不接收外部的数据(把外部的地址传进来),在内部进行初始化,并把方法的结果返回带给实参
所以第五行和第六行都是 15;
out参数用的比较多,使用带out参数可以使我们避免大量使用try catch 语句
例子如下
string value = "ab";
int num;
//out传递也是变量的地址,内部给这个变量赋值
if (int.TryParse(value, out num))//转换成功就返回true,并把结果存储在变量num中
{
Console.WriteLine("转换成功:" + num);
}
else {
Console.WriteLine("转换失败");
}
如果我们不加out这个参数,那就要使用try catch 语句 TryParse返回 true,false两个结果,用num去接收(相当于初始化)
并返回两个结果 转换成功,转换失败。
看完了值类型的传递我们来看引用类型的参数传递
/// <summary>
/// 引用类型的参数传递
/// </summary>
public class ClassParams
{
public void Say1(Person p)
{
Console.WriteLine("say1:1"+p.name); // fashi
p = new Person();
p.name = "xue";
Console.WriteLine("say2:2"+p.name); //xue
}
public void Say2(ref Person p)
{
Console.WriteLine("say2:1"+p.name); //fashi
p = new Person();
p.name = "xue";
Console.WriteLine("say2:2" + p.name); //xue
}
public void Say3(out Person p)
{
p = new Person();
p.name = "xue";
Console.WriteLine("say3:"+p.name);//xue
}
}
public class Person
{
public string name;
}
static void Main (String []args)
{
ClassParams p2 = new ClassParams();
Person p = new Person();p.name = "fashi";
p2.Say1(p);
Console.WriteLine("Main" + p.name); //fashi
p2.Say2(ref p);
Console.WriteLine("Main" + p.name); //xue
p2.Say3(out p);
Console.WriteLine("Main" + p.name);//xue
}
方法里面的输出都很容易理解,我们来讲一下Main方法里的输出,第一调用没有参数传递的引用类型,Main里面输出fashi
第二种带参数的ref 为什么输出的是xue,因为调用带ref参数的方法把 p指向的xue的地址赋值给了p指向fashi的地址,所以Main里面输出的是fashi
第三种带参数的out的不接收方法里的参数,并把自己的初始化的地址赋值给了p指向的fashi的地址,所以Main里面输出的是xue
我们现在来总结一下
*ref,out:传递值类型的变量的地址;
* ref:传递过程中保留初始值;
* out:传递过程中不保留初始值;
* ref:一般需要把外部的值传入到方法中使用并进行修改;
* out:一般传递变量进入某个方法中接收数据;