C#中string为引用类型,为何无法在扩展方法中修改其值?
问题原因解答
你遇到的这个问题和string的特殊表现没有关系,本质是C#的参数传递规则导致的,和所有引用类型的默认传参行为一致:
- C#中所有参数默认都是按值传递,不管是值类型还是引用类型。
- 对于引用类型来说,按值传递时,方法拿到的是「指向堆中对象的引用的副本」:也就是说你扩展方法里的
input变量,和外部的test变量是两个完全独立的存储单元,只是初始状态下它们指向堆上的同一个字符串对象。 - 你在方法内执行
input = input.Remove(startingIndex, length);,只是把方法内部的input这个引用副本指向了Remove返回的新字符串对象,完全不会修改外部test变量的指向,自然外部的test值不会变。
你可以换任意其他自定义引用类型做测试,都会得到一样的结果,比如下面的示例:
public class MyClass { public int Value { get; set; } } public static void TestExtension(this MyClass obj) { // 这里修改的只是方法内obj这个引用副本的指向,外部变量不会变 obj = new MyClass { Value = 2 }; } // 调用代码 var myObj = new MyClass { Value = 1 }; myObj.TestExtension(); Console.WriteLine(myObj.Value); // 输出还是1
你提到的string不可变特性是另一个概念:它指的是堆上的字符串对象本身一旦创建就无法修改,所以Substring、Remove等方法都只会返回新的字符串对象,而不会改动原对象。这个特性只是决定了你必须给input重新赋值才能拿到修改后的字符串,和你当前遇到的「赋值不影响外部变量」的问题无关。
你自己实现的带ref参数的方案能生效,也刚好印证了上面的逻辑:加了ref之后参数变成按引用传递,方法拿到的是外部变量本身的存储地址,修改方法内的input就会直接同步修改外部变量的指向,自然就生效了。
内容的提问来源于stack exchange,提问作者Taco
相关产品推荐
相关产品推荐

