c#:在传递引用类型的值之后,更改外部的值会影响对象吗?
在下面的代码中,我初始化了客户机并将其传递给新工作类的构造函数。然后,当两个worker仍在运行时,我将该值设置为null。据我所知,我正在为构造函数中的引用类型执行一个传递值,因此p.myClient和worker1.client应该指向堆上的同一个客户机对象。但是为什么它不抛出一个NullPointerException呢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")
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参数传递。
。谢谢提供对属性或索引器的引用将对并发特性产生影响。