在C#中传递引用类型

时间:2013-09-13 13:27:08

标签: c#

class Test
{
    static void Func(StringBuilder myString)
    {
        myString.Append ("test");
        myString = null;
    }
    static void Main()
    {
        StringBuilder s1 = new StringBuilder();
        Func(s1);
        Console.WriteLine (s1);
    }
}

输出为“Test”,为什么不为null?

如果s1通过引用 传递给Func(),那么为什么myString.Append("test")会更改它,但myString = null不会?

提前致谢。

5 个答案:

答案 0 :(得分:11)

您按值传递对象的引用。

即。对象的地址按值传递,但对象和对象的地址是相同的。因此,当您调用方法时,VM会复制引用;你只是在改变副本。

myString.Append上,您使用复制的引用来获取对象(仍然只有一个对象),然后更改/调用该对象。

你认为你正在做的是:

class Test
{
    static void Func(ref StringBuilder myString)
    {
        myString.Append("test");
        myString = null;
    }
    static void Main(string[] args)
    {
        StringBuilder s1 = new StringBuilder();
        Func(ref s1);
        Console.WriteLine(s1);
    }
}

更长的解释:http://javadude.com/articles/passbyvalue.htm

答案 1 :(得分:10)

  

如果通过引用Func()传递s1,那么为什么呢   myString.Append(“test”)确实改变了它

它没有通过引用传递,而是将其地址值传递给函数。

假设S1指向内存位置0x48,这将传递给Func,其中Func参数myString将开始指向该位置。稍后当您Append到该位置的文本时,会添加该文本。但是稍后当您将null分配给myString时,它会开始指向任何内容,但原始位置保持不变。

您应该看到:Parameter passing in C# by Jon Skeet

请考虑以下图表。 在第1步中,您将创建一个StringBuilder类型的新对象,并让S1引用该对象。

enter image description here

在第2步中,将S1传递给Func后,现在myString也指向内存中的同一个对象。

enter image description here

稍后当您Append通过myString发送文本时,它会更新原始对象,因为myString指向对象持有的内存位置。

在步骤3中,当您为myString分配null时,它会丢失StringBuilder对象的地址,但这不会更改对象或指针S1中的任何内容。

enter image description here

答案 2 :(得分:2)

在C#中,默认情况下,复数类型的指针(引用)按值传递。您必须指定它是通过引用传递的,如下所示:

static void Func(ref StringBuilder myString)
{
    myString.Append ("test");
    myString = null;
}

答案 3 :(得分:0)

ref添加到函数中以通过ref。

传递它
static void Func(ref StringBuilder myString)
{
    myString.Append ("test");
    myString = null;
}

然后称之为:

Func(ref s1);

答案 4 :(得分:0)

因为您将StringBuilder s1的引用传递给Func。 在Func中,对同一个StringBuilder实例的引用称为“myString”。 您首先告诉它做某事(“myString.Append("Test")),然后将引用INSIDE Func设置为null。Append的结果对Main()可见;引用设置为null不会影响Main中的s1。” / p>