3

我正在读约翰斯基特的书"C# in Depth"。他在第 74 页上说,每个人都假设通过引用传递给函数的参数,同时它是通过值传递的,并且作为示例,他展示了这段代码,该代码必须证明调用代码中的 StringBuilder 没有改变。与此同时,我们的函数 StringBuilder 实例内部发生了变化。

private static void SayHello(StringBuilder s)
 {
   s.AppendLine("Hello");
 }

但是我的实验表明 StringBuilder 对象发生了变化——我们将在控制台中看到“Hello”。这里有什么问题?或者我对这个例子的理解有什么问题?

       private static void Main(string[] args)
        {
           var s  = new StringBuilder();
            Console.WriteLine(s.ToString());
            SayHello(s);
            Console.WriteLine(s.ToString());
            Console.ReadLine();
        }

        private static void SayHello(StringBuilder s)
        {
            s.AppendLine("Hello");
        }
4

2 回答 2

4

读完那页,他说的是这个。

现在请记住,引用类型变量的值是引用,而不是对象本身。您可以更改参数引用的对象的内容,而无需通过引用传递参数本身。

    public static void Main()
    {
        var s = new StringBuilder();
        Console.WriteLine(s.ToString());
        SayHello(s);
        Console.WriteLine(s.ToString());
        Console.ReadLine();
    }

    private static void SayHello(StringBuilder s)
    {
        s.AppendLine("Hello");
        s = null;
    }

    //output will be Hello

调用此方法时,参数值(对 StringBuilder 的引用)按值传递。如果我要在方法中更改 builder 变量的值——例如,使用语句 builder = null;——调用者不会看到这种变化,这与神话相反。

所以他几乎解释说你不能StringBuilder在 SayHello 中销毁对象,你可以改变这个对象的内容。我也不知道。

编辑:关于你的评论

几乎当你传入sSayHello 时,你正在创建新的引用,并且在Main方法中引用和在SayHello引用同一个对象。但它们就像 2 个不同的参考一样存在。

如果你写在

private static void SayHello(StringBuilder s)
{
    s.AppendLine("Hello");
    s = new StringBuilder();

}

s in 的引用SayHello将指向另一个对象,但这不会改变 Main 方法中的任何内容,因为该引用指向您写 Hello 的前一个对象。所以再次输出将是Hello。

如果你想通过你应该使用的确切参考ref

所以如果你写

private static void SayHello(ref StringBuilder s)
{
     s.AppendLine("Hello");
     s = null;
     //you will receive an exception in Main method, because now the value in the reference is null.
}
于 2016-10-13T03:36:03.730 回答
1

考虑以下类比:

  1. 您购买了新公寓 ( new StringBuilder()) 并获得了授予您访问权限的密钥 ( s)。
  2. 你雇了一个清洁工 ( s.AppendLine),然后给他一份你的钥匙副本,这样他就可以进入你的公寓并清理它。
  3. 清洁工使用你的钥匙副本,清理你的公寓,并且因为他喜欢它,所以重新编程钥匙以打开其他公寓。
  4. 你完成了你的日常工作,然后回到家。你的钥匙可以很好地打开你公寓的门,你会发现它很干净。

这基本上就是按值传递引用类型时发生的情况。

现在考虑以下几点:

  1. 您购买了新公寓 ( new StringBuilder()) 并获得了授予您访问权限的密钥 ( s)。
  2. 你雇了一个清洁工(s.AppendLine),然后把钥匙给他这样他就可以打扫你的公寓了。
  3. 清洁工清理了你的房间,因为他喜欢,所以重新编程了你给他的钥匙来打开其他公寓。他把你的钥匙放在门垫下面。
  4. 你完成了你的日常工作,然后回到家。你试图用你的钥匙,但门打不开。透过窗户你可以看到你的公寓很干净。

这就是通过引用传递引用类型时发生的情况。

于 2016-10-13T05:40:46.187 回答