C#中值类型参数与引用类型参数的简单讨论

先看一个简单的例子。

 

我们建立一个Console Application.

写一个Class,

代码
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

posted @ 2010-10-01 18:32  idealcat  阅读(578)  评论(0编辑  收藏  举报