c#:引用类型按值传递后,更改外部值会影响对象吗?

c#: after pass by value for a reference type, would changing the value outside affect the object?

在下面的代码中,我初始化了客户端并将其传递给新 Worker 类 的构造函数。然后我将值设置为 null,而这两个工作人员仍然 运行。据我了解,我在构造函数中对引用类型进行按值传递,因此 p.myClient 和 worker1.client 应该指向堆上的同一个 Client 对象。但为什么它不抛出 NullPointerException?

class Client
{
    public Client()
    {
        Console.WriteLine("creating client");
    }

    public void Go(string s)
    {
        Console.WriteLine("go {0}", s);
    }
}

class Worker
{
    private int invokeCount;

    Client client;
    public Worker(Client c)
    {
        client = c;
    }

    public void Pull(Object stateInfo)
    {
        Console.WriteLine("{0} Pulling {1,2}.",
            DateTime.Now.ToString("h:mm:ss.fff"), (++invokeCount).ToString());
        client.Go("pull");
    }

    public void Push(Object stateInfo)
    {
        Console.WriteLine("{0} Pushing {1,2}.",
            DateTime.Now.ToString("h:mm:ss.fff"), (++invokeCount).ToString());

        client.Go("push");
    }
}

class Program
{
    Client myClient = new Client();

    static void Main()
    {
        Program p = new Program();

        var worker1 = new Worker(p.myClient);
        Console.WriteLine("{0:h:mm:ss.fff} Creating timer.\n", DateTime.Now);
        var stateTimer = new Timer(worker1.Push, null, 1000, 400);

        var worker2 = new Worker(p.myClient);
        Console.WriteLine("{0:h:mm:ss.fff} Creating timer.\n", DateTime.Now);
        var stateTimer2 = new Timer(worker2.Pull, null, 1000, 400);

        p.myClient = null;

        Console.ReadKey();
        stateTimer.Dispose();
        Console.WriteLine("\nDestroying timer.");
        Console.Read();
    }
}

您试图一次讨论太多事情:"pass by value"、"reference type" 和 "heap"。

在 C# 中,唯一不按值传递的方法是使用 outref。它们需要一个变量(本地、字段、属性、 参数),而按值传递只需要一个表达式(一个值)。

但是,none 这些概念甚至是相关的。

关键是赋值是一种浅层的值复制操作。

client = c; 复制字段中的值。没有其他代码设置该字段,因此它保持相同的值 "forever"。 (您可能应该使用 readonly 修饰符。)

p.myClient = null 删除 p 的值副本。由于没有该值的其他副本可用(worker1.clientworkder2.client 是私有的),它不能再使用它。 (一个好的静态分析器会在那里标记该语句,因为设置的变量之后不会在任何地方读取,从而提出您的代码是一个不完整的想法的问题。)