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

c#:在传递引用类型的值之后,更改外部的值会影响对象吗?,c#,.net,multithreading,pass-by-value,C#,.net,Multithreading,Pass By Value,在下面的代码中,我初始化了客户机并将其传递给新工作类的构造函数。然后,当两个worker仍在运行时,我将该值设置为null。据我所知,我正在为构造函数中的引用类型执行一个传递值,因此p.myClient和worker1.client应该指向堆上的同一个客户机对象。但是为什么它不抛出一个NullPointerException呢 class Client { public Client() { Console.WriteLine("creating client")

在下面的代码中,我初始化了客户机并将其传递给新工作类的构造函数。然后,当两个worker仍在运行时,我将该值设置为null。据我所知,我正在为构造函数中的引用类型执行一个传递值,因此p.myClient和worker1.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();
    }
}

您试图同时讨论太多的事情:“传递值”、“引用类型”和“堆”

在C#中,不通过值传递的唯一方法是使用
out
ref
。它们需要一个变量(局部、字段、属性、参数),而传递值只需要一个表达式(值)

但是,这些概念甚至都不相关

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

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


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

myClient
是一个参考变量。它指向内存中的一个对象。当您将其(按值)传递给工作程序时,该工作程序现在对同一对象拥有自己的引用变量。稍后,当您将
myClient
设置为null时,您也不会将其他引用重新指向null。它们仍然指向原始对象。类似地,如果您这样做:
var foo=new Client();var-bar=foo;foo=null
foo
现在将为
null
,而
bar
仍然指向foo创建的对象。引用类型的值就是引用。这可能会让人混淆,因为您可以使用引用修改对象,也可以修改它指向的地址,这是两件不同的事情。当你把
myClient
传递给一个工作人员时,你在说,“嘿,看看这个地址!”。如果以后修改该地址的某些内容,比如更改属性值,那么在这种情况下,所有引用现在都将指向具有新值的同一对象。区别在于,当您将引用分配给其他对象(如
null
)时,您给它一个新的地址来指向。您没有在同一地址放置新对象。谢谢大家,现在有意义了!属性未分类为变量,但ref返回属性(以及任何其他ref返回方法)除外。@PetSerAl您是对的:
CS0206属性或索引器不能作为out或ref参数传递。
。谢谢提供对属性或索引器的引用将对并发特性产生影响。