我遇到了这个棘手的问题。请参阅以下代码:
public class Foo
public int A { get; set; }
}
static void Main(string[] args)
{
Foo foo1 = new Foo();
Foo foo2 = new Foo();
ChangeObject1(foo1);
ChangeObject2(ref foo2);
Console.WriteLine("Foo1 = " + foo1.A);
Console.WriteLine("Foo2 = " + foo2.A);
Console.ReadKey();
}
static void ChangeObject1(Foo foo)
{
foo.A += 1;
foo = new Foo();
}
static void ChangeObject2(ref Foo foo)
{
foo.A += 1;
foo = new Foo();
}
经过一些测试,foo1.A等于1,而foo2.A仍然等于0。据我了解,这是因为第二个方法通过引用而不是值传入实例。这会更改实例的内容,因此当在方法中创建并分配新对象时,不再定义该值。
但是想到这一点让我很困惑,因为我觉得第一个方法应该有类似的效果,即使它是按值传递的,因为实例的内容仍然在方法之外更改。
有人知道到底发生了什么吗?谢谢!
最佳答案
我假设您使用的是 c# 或 java。无论哪种方式,概念都是一样的
当你声明 foo 变量时
Foo foo1 = new Foo()
您正在声明所谓的引用类型。 (所有代表类的对象都是引用类型)
所以,存储在 foo1
中的值并不是真正的 Foo
,但它是一个保存该 Foo
内存地址的值.
当你打电话
static void ChangeObject1(Foo foo)
{
foo.A += 1;
foo = new Foo();
}
您正在传递该引用的副本。因此,当您执行 foo.A += 1
时,您正在更改刚刚传入的对象的成员值。
当您执行 foo = new Foo();
时,您只是更改了引用的副本,而不是原始对象引用本身。
现在,当你打电话时
static void ChangeObject2(ref Foo foo)
{
foo.A += 1;
foo = new Foo();
}
您传递的不是 Foo
地址的副本,而是传递 Foo
地址的地址。
您可以将其视为传递原始 Foo
地址本身。
因此,当您调用 foo = new Foo()
时,之前对 foo 做了什么并不重要。您刚刚用全新的 Foo
对象的地址覆盖了您的地址。
如果您将方法更改为如下所示
static void ChangeObject2(ref Foo foo)
{
foo.A += 1;
}
那么你应该注意到变化
Here's a page that explains reference types它是用 java 编写的,但同样的原理也适用于 c#
关于c# - 为什么传入带有 ref 关键字的方法的实例在创建新对象后可以保持不变?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12375678/