You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#值传递引用类型时new不覆盖原对象及传值传引用的原理疑问

搞懂C#里的按值传递与引用类型的那些坑

我太懂这种越想越绕的感觉了——C#里的按值传递因为引用类型的存在,确实很容易让人混淆。咱们一步一步拆解你的问题,把底层逻辑理清楚:

先明确核心规则:C#默认都是按值传递

不管你传的是int这种值类型,还是Book这种引用类型,默认都是按值传递。这里的关键是:

  • 传值类型时,传递的是数据本身的副本;
  • 传引用类型时,传递的是对象引用的副本——划重点,是「引用的副本」,不是引用本身!

第一个例子:为什么修改属性会影响原对象?

看你这段代码:

Book book1 = new Book("Fight club");
ChangeBookName(book1, "The Wolfman");
void ChangeBookName(Book book, string name){ book.Name = name; }

底层发生的事是这样的:

  1. new Book("Fight club") 在托管堆上创建了一个Book实例,然后返回一个指向这个堆内存地址的引用,把这个引用存在栈上的book1变量里。
  2. 调用ChangeBookName时,把book1里的那个地址值复制了一份,传给方法里的book参数(这个参数也是栈上的局部变量)。
  3. 这时候book和book1指向的是堆里同一个Book对象,所以book.Name = name本质是修改了堆里那个共同对象的属性,外部的book1自然能看到这个变化。

第二个例子:为什么new之后原对象没变化?

再看这段代码:

Book book1 = new Book("Fight club");
ChangeBookName(book1, "The Wolfman");
void ChangeBookName(Book book, string name){ book = new Book(name); }

前两步和上面一样:book参数拿到了book1引用的副本,指向同一个堆对象。但第三步不一样:

  • new Book(name) 在堆里新建了一个完全独立的Book实例,得到一个新的内存地址;
  • 然后book = new Book(name)是把方法内部的book参数里的地址值替换成了新对象的地址;
  • 但栈上的book1变量里的地址根本没动,它还是指向最初的"Fight club"对象。所以外部的book1.Name自然还是原来的值。

解答你的几个疑问

1. 为什么new关键字不会覆盖原来的对象引用?

因为你传递的是引用的副本,不是原始引用本身。方法里修改的只是局部参数的引用,和外部的book1半毛钱关系都没有——就像你复制了一把家里的钥匙,然后把复制的钥匙改成开邻居家的门,你原来的钥匙还是开自己家的门。

2. new关键字是否创建了新的对象引用?

是的。new会在堆上分配新的内存空间创建对象,然后返回一个指向这个新空间的引用。这个新引用只会存在于方法内部的book参数里,除非你用ref/out把原始引用传进去。

3. 传递的原始值去向何方?

传递的原始引用副本还在方法的局部参数里,但当你给book赋值新引用后,原来的副本就被覆盖了——不过这无关紧要,因为它本来就是个副本,外部的原始引用book1一直没变。

4. 为什么新的Book实例没有覆盖旧实例?

因为两个实例在堆里是完全独立的内存块,一个是最初的"Fight club",一个是新的"The Wolfman"。book参数只是从指向旧块改成指向新块,旧块依然存在,book1还是指着它。

怎么让外部引用指向新对象?

如果想让book1也指向新创建的对象,你需要用ref关键字,把引用本身按引用传递:

Book book1 = new Book("Fight club");
ChangeBookName(ref book1, "The Wolfman");
void ChangeBookName(ref Book book, string name){ book = new Book(name); }

这时候传递的就不是引用的副本了,而是原始引用的「别名」,方法里修改book的引用,就等同于修改外部的book1引用。

内容的提问来源于stack exchange,提问作者user13192625

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 23:02:35