关于C#里的引用一直没有个清楚的认识,特别是对应传参时ref的运用。现在试着了解一下以理清概念。
首先,我们都知道在C#里有两种类型:值类型与引用类型。
对于值类型比较简单,如果作为参数传递时是拷贝传入,所以说在函数里改变参数是不会修改源数据。如果要同时修改源数据,就可以加上ref。
对于引用类型就比较麻烦。首先,所有的类在C#中都是引用。但是其中string类是奇怪的,虽然string类是引用,但是由于一旦给string赋值,那么它的值是不能修改的,所以在给string改值时,其实是重新给string指向一个新的地址, 因此要想改变原值就需要加上ref。
至于其他的类,什么时候要加ref,什么时候不需要加ref呢?
一个类作为参数传递是其实传递的是它的引用,其引用指向这个类的内存。因此无论函数里外,这个引用都是指向同一个内存, 所以如果只是想修改这个内存你的值可以直接修改,不需要加ref。但是如果要修改这个引用所指向的内存,就是说让这个引用指向新的内存(比如是new操作),那这时就需要加上ref才能保证传入的参数能被改变。
简单的列子,我们来试着交换两个引用值:
//测试类 class Test { public string Name {get;set} } //测试函数1 void Swap_without_ref(Test test1, Test test2) { Test _t = test1; test1 = test2; test2 = _t; } //测试函数2 void Swap_with_ref(ref Test test1, ref Test test2) { Test _t = test1; test1 = test2; test2 = _t; }
static void Main()
{
Test test1 = new Test{ Name = "a" };
Test test2 = new Test{ Name = "b" };
Swap_without_ref(test1, test2); //test1,test2的值没有改变
Swap_with_ref(ref test1, ref test2); //test1,test2的值相互交换了
}
接下来我们把Test类改一下, 这回我们只改Test类中包含的类Case。
//测试类 class Case { public string Name {get;set;} } class Test { public string Name {get;set;} public Case Case {get;set;} }
//测试函数1 void Swap_Case(Test test1, Test test2) { test1.Case = test2.Case }
static void Main()
{
Test test1 = new Test{ Name = "a" , new Case{ Name = "a" }};
Test test2 = new Test{ Name = "b" , new Case{ Name = "b" } };
Swap_Case(test1, test2); //test1的case值改变
}