C#中值类型参数与引用类型参数的简单讨论
先看一个简单的例子。
我们建立一个Console Application.
写一个Class,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class A{
public string Name { get; set; }
public string Description { get; set; }
public A(string name, string description)
{
Name = name;
Description = description;
}
}
然后在入口程序中,
class Program
{
//* Local Class
static void Main(string[] args)
{
A a1 = new A("Betty", "dog");
A a2 = new A("Betty", "dog");
A a3 = new A("Betty", "dog");
A a4 = new A("Betty", "dog");
A a5 = new A("Betty", "dog");
// a1
Foo1(a1);
Console.Write(string.Format("{0} is a {1}", a1.Name, a1.Description));
Console.WriteLine();
// a2
Foo2(a2);
Console.Write(string.Format("{0} is a {1}", a2.Name, a2.Description));
Console.WriteLine();
// a3
Foo3(ref a3);
Console.Write(string.Format("{0} is a {1}", a3.Name, a3.Description));
Console.WriteLine();
// a4
Foo4(a4);
Console.Write(string.Format("{0} is a {1}", a4.Name, a4.Description));
Console.WriteLine();
// a5
Foo5(ref a5);
Console.Write(string.Format("{0} is a {1}", a5.Name, a5.Description));
Console.WriteLine();
Console.ReadLine();
}
private static void Foo1(A a)
{
a.Description = "cat";
}
private static void Foo2(A a)
{
a = new A("Cynthia", "cat");
}
private static void Foo3(ref A a)
{
a = new A("Cynthia", "cat");
}
private static void Foo4(A a)
{
Foo1(a);
}
private static void Foo5(ref A a)
{
a = new A("Cynthia", "cat");
Foo1(a);
}
// * */
}
}
OK, 输出结果为,
Betty is a cat
Betty is a dog
Cynthia is a cat
Betty is a cat
Cynthia is a cat
在C#,Class类型作为参数的话,是Passing reference types by value(按值传递引用类型)。方法Foo1,Foo2,Foo4属于这种情况。
如果使用ref操作符,则为Passing reference types by reference(按引用传递引用类型)。方法Foo3,Foo5属于这种情况。
其实都可以理解为Passing value types(按值传递)。Reference实质上也是一个value,当传入方法时,内部会有一个临时变量存之。这种储存始终是一种值传递。
Passing reference types by value,就是将地址存入方法中的内部临时变量中,对此的操作,会使公共语言运行时找到引用所指向的对象进行操作。但是当把这个变量赋予一个新的类的时候,实质上是改变了它的引用。原来的类在方法中失去任何指向它的引用。
Passing reference types by reference, 将地址存入方法中的内部临时变量中,但是这个内部临时变量也是一个reference。所以对它的操作完全等同于对原来那个引用的操作。
举些例子来说明。
邮局有一个邮件包裹需要你去领取。邮局先会派人把领取的票送给你(当然,这个流程是我假设的)。包裹是这个Class A,领取的票就是它的引用。
很可惜你不在家,但是你想了方法,在大门上贴了一张纸,好让邮局的人把票上的信息抄写在纸上,等你回来再去领取。与此同时呢,你的邻居也有一个包裹邮件,同时也不在家。
你的包裹是个很可爱的玩具狗,现在邮局派人给你送票,当然你不在家,只好把票上的信息在门上抄给你。
1. 邮差很粗心, 他把狗写成了猫。 后来你去邮局拿的到了一个叫Betty的猫。(好吧,假设有叫Betty的猫给你) -> Foo1
2. 邮差看走了眼,把给邻居的单子抄给了你。不过你的单子实质上还是原来的样子,你发现了以后去邮局找到自己的单子,拿到了叫Betty的狗。 -->Foo2
3. 邮差看走了眼,把给邻居的单子抄给了你。不过你也没抱怨,就把邻居的单子当成自己的,拿了邻居家的那个叫Cynthia的猫。-->Foo3
4. 你真的是太懒了,对于门上的单子你都懒得跑去拿,专门请了个人帮你拿单子,虽说多了一步,但是单子还是那张单子,拿到了叫Betty的猫。-->Foo4
5. 你把邻居家的单子当成自己的,还专门找人去把邻居家门上的单子拿给你,于是拿了邻居家的那个叫Cynthia的猫。-->Foo5
接下来,来说一下Passing value types by value和Passing value types by reference。
一般的值类型如果没有使用ref操作符的都是Passing value types by value,使用ref的是Passing value types by reference。
最常见的例子的就是互换两个数的值,当然这个过于简单我就不赘述了。
如果你很清晰的话,那么我们来加大点难度。
我们来构建一个WebService,只有一个简单的方法,
[WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] public class WebService1 : System.Web.Services.WebService { [WebMethod] public void WebFoo(int[] a) { a[0] = 9999; } }
我们再改一改入口程序
class Program { //* static void Main(string[] args) { localhost.WebService1 webservice = new localhost.WebService1(); int[] arr = new int[] { 1, 2, 3 }; Print(arr); webservice.WebFoo(arr); Print(arr); Console.ReadLine(); } private static void Print(int[] a) { foreach (int i in a) { Console.Write(i); Console.WriteLine(); } } // */ }
那么输出是什么呢?达人们都笑了,对,还是1 2 3