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

C#中方法调用影响对象但赋值仅改引用的原因及解决方案

C#引用类型参数传递的常见困惑解答

先看你给出的代码:

public void Foo(StringBuilder sb) {
    sb.Append("test");     
    sb = null; 
}  

StringBuilder myStringBuilder = new StringBuilder(); 
Foo(myStringBuilder); 
Console.WriteLine(myStringBuilder.ToString()); // 仍输出"test" 

1. 底层原理:为什么sb = null不影响外部的myStringBuilder

C#里默认的参数传递是值传递,哪怕是引用类型也不例外。核心要区分「引用本身」和「引用指向的对象」:

  • 调用Foo(myStringBuilder)时,方法内部的sb是外部myStringBuilder的引用副本——相当于把写着房子地址的纸条复印了一张,原纸条和副本都指向同一栋房子。
  • sb.Append("test")是通过副本上的地址,找到堆里的StringBuilder对象并修改内部内容,原引用myStringBuilder指向的是同一个对象,所以能看到修改后的结果。
  • sb = null是把副本纸条上的地址擦掉,让它变成空白,但原纸条上的地址还在,指向的房子也没消失,所以外部的myStringBuilder完全不受影响。

简单说:修改引用指向的对象,会影响所有指向该对象的引用;但修改引用本身(比如赋值null),只会改变当前这个引用变量,和其他引用无关。

2. 如何在方法内将原引用设为null?用ref关键字

如果要让方法内的操作直接修改外部的引用变量,需要用ref关键字,它的作用是传递引用变量本身的引用(相当于把原纸条递进去,而不是递副本)。

修改后的代码示例:

// 方法定义时添加ref关键字
public void Foo(ref StringBuilder sb) {
    sb.Append("test");     
    sb = null; 
}  

StringBuilder myStringBuilder = new StringBuilder(); 
// 调用时也要添加ref关键字
Foo(ref myStringBuilder); 
Console.WriteLine(myStringBuilder == null); // 输出True

ref的工作机制:

  • 使用ref后,方法内部的sb不再是原引用的副本,而是直接关联到外部的myStringBuilder变量本身。
  • 此时sb = null就是直接修改外部变量的指向,把myStringBuilder的引用改成null,外部自然能看到这个变化。
  • 注意:调用带ref参数的方法时,必须在实参前也加ref,而且实参必须是已经初始化的变量(不能传null或者未赋值的变量)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 11:42:38