真的是价值传递的论点吗?

时间:2016-10-13 03:23:00

标签: c# pass-by-value byval

我正在阅读John Skeet的书"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");
        }

2 个答案:

答案 0 :(得分: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
  

调用此方法时,参数值(对a的引用)   StringBuilder)按值传递。如果我要改变的价值   方法中的构建器变量 - 例如,使用语句   builder = null;相反,调用者不会看到更改   到了神话。

所以他解释说你不能破坏SayHello中的对象StringBuilder,你可以只改变这个对象的内容。我也不知道。

编辑:关于您的评论

当你在SayHello中传递s时,你正在创建新的引用,Main方法和SayHello中的引用都引用同一个对象。但它们就像2个不同的参考文献一样存在。

如果你写的话

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

}

SayHello中s的引用将指向另一个对象,但这不会更改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.
}

答案 1 :(得分:1)

考虑以下类比:

  1. 您购买了一套新公寓(new StringBuilder())并获得了一张授予您访问权限的密钥(s)。
  2. 你雇用了一名清洁工(s.AppendLine)并且给了他一把钥匙的副本,这样他就可以进入你的公寓并进行清理。
  3. 清洁工使用你的钥匙副本,打扫你的公寓,因为他觉得这样,重新编程钥匙打开其他公寓。
  4. 你完成了日常工作并回到了家里。你的钥匙就可以打开通往你公寓的大门,你会发现它很干净。
  5. 基本上当你按值传递引用类型时会发生什么。

    现在考虑以下事项:

    1. 您购买了一套新公寓(new StringBuilder())并获得了一张授予您访问权限的密钥(s)。
    2. 你雇用了一名清洁工(s.AppendLine)并且给了他你的钥匙,以便他可以清理你的公寓。
    3. 清洁工清理你的房间,因为他觉得这样,重新编程你给他打开其他公寓的钥匙。他把钥匙放在门垫下面。
    4. 你完成了日常工作并回到了家里。你试着用你的钥匙,但门不会打开。透过窗户可以看到你的公寓很干净。
    5. 这是通过引用传递引用类型时会发生什么。