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

输出是“测试”,为什么不为空?

如果 s1 是通过对 Func()的引用传递的,那么为什么要myString.Append("test")更改它,但myString = null没有呢?

提前致谢。

4

5 回答 5

12

您正在按值传递对对象的引用。

即对象的地址是按值传递的,但是对象和对象的地址是一样的。因此,当您调用方法时,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

于 2013-09-13T13:29:22.737 回答
10

如果 s1 是通过引用 Func() 传递的,那么为什么 myString.Append("test") 会改变它

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

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

您应该看到:Jon Skeet 在 C# 中传递的参数

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

在此处输入图像描述

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

在此处输入图像描述

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

在第 3 步中,当您将 null 分配给myString它时,它会丢失StringBuilderobject 的地址,但这不会改变 object 或指针中的任何内容S1

在此处输入图像描述

于 2013-09-13T13:31:38.640 回答
2

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

static void Func(ref StringBuilder myString)
{
    myString.Append ("test");
    myString = null;
}
于 2013-09-13T13:30:49.337 回答
0

添加ref到函数以通过 ref 传递它。

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

然后这样称呼它:

Func(ref s1);
于 2013-09-13T13:30:33.807 回答
0

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

于 2013-09-13T13:33:22.460 回答