C#引用类型按ref传递后赋值新对象,堆内存地址是否改变?
C#中ref传递引用类型时对象地址变化的疑问解答
你的理解是正确的:当引用类型通过ref关键字传递给方法时,在方法内给参数赋值新对象,主函数中的原变量(比如你的t1)确实会指向新的对象,它的引用地址应该发生变化。
你看到地址保持不变,大概率是验证过程中出现了误解或者调试工具的显示问题。我们结合你的代码来拆解整个过程:
- 初始状态:
Test t1 = new Test() { a = 10 };此时t1指向内存中一个新创建的Test对象,假设这个对象的地址是地址A。 - 传递参数:调用
GetCallByRefForObj(ref t1)时,ref关键字让方法内的参数x成为t1变量本身的引用——也就是说,x和t1是同一个变量的不同名字,它们指向同一个对象(地址A)。 - 赋值新对象:在方法内执行
x = new Test() { a = 10 };,这会创建一个新的Test对象(地址B),并让x(也就是t1)指向这个新对象。此时主函数中的t1已经不再指向原来的地址A,而是地址B。
如果想准确验证地址变化,可以在代码中添加打印对象地址的逻辑,比如:
using System.Runtime.InteropServices; class Test { public int a { get; set; } } class Program { static void Main(string[] args) { Test t1 = new Test() { a = 10 }; Console.WriteLine($"调用方法前,t1指向的对象地址: {GetObjectAddress(t1)}"); GetCallByRefForObj(ref t1); Console.WriteLine($"调用方法后,t1指向的对象地址: {GetObjectAddress(t1)}"); } public static void GetCallByRefForObj(ref Test x) { x = new Test() { a = 10 }; } private static long GetObjectAddress(object obj) { return Marshal.GetIUnknownForObject(obj).ToInt64(); } }
运行这段代码,你会看到前后打印的地址完全不同,这就证明t1的引用确实指向了新的对象。
你之前的验证结果(地址不变),可能是因为调试时在赋值新对象前查看了t1的地址,之后没有重新查看;或者调试工具显示的是原对象的地址,而非t1当前指向的地址。
内容的提问来源于stack exchange,提问作者Rajaram Shelar
相关产品推荐
相关产品推荐

