我想更多地了解ref关键字的工作原理,因此我做了以下实验:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var main = new Main { Property = 1 };
var dependent = new Dependent(main);
void ChangeRef(ref Main Oldmain, Main newMain)
{
Oldmain = newMain;
}
ChangeRef(ref main, new Main { Property = 5 });
Assert.AreEqual(5,dependent.Main.Property);
}
}
public class Main
{
public int Property { get; set; }
}
public class Dependent
{
public Dependent(Main main)
{
Main = main;
}
public Main Main { get; set; }
}
正如你所看到的那样,我希望能够在保留引用的同时替换main引用的对象,但是测试失败并且值仍然是1.有人可以详细说明为什么那不起作用或指向我到一个我可以阅读更多的地方?
更新: 就像有人在下面回答,但后来删除了。 如果我通过引用传递主对象到构造函数中的依赖项,它为什么不起作用? 难道他们都没有相同的参考?
答案 0 :(得分:2)
正如其他人指出的那样,您无法立即使程序中的所有变量和字段指向不同的实例。
但是如果你想反映程序所有部分的变化,最简单的方法是将它包装在不同的类中(比如你的Dependent
类)。然后,您可以与程序的其他部分共享该类,并改为改变其属性:
class SomeOtherObject
{
readonly Dependent _dependent;
public Dependent { get { return _dependent; }}
public SomeOtherObject(Dependent dependent)
{
_dependent = dependent;
}
public void Print()
{
Console.WriteLine(_dependent.Main.Property);
}
}
所以现在你可以这样做:
var dependent = new Dependent(new Main { Property = 1 });
var someOtherObject = new SomeOtherObject(dependent);
// this will print "1"
someOtherObject.Print();
dependent.Main = new Main { Property = 5; };
// this will print "5"
someOtherObject.Print();
在这种情况下,显然,只需更改dependent.Main.Property
也可以。因此,如果程序的所有部分都指向一个对象,您可以改变它(即更改其内部数据),每个人都会看到更改,但是您无法使程序的所有部分都改变它们所指向的内容。
值得注意的是,在多线程程序中执行此操作时需要小心;你很少想要其他一些线程能够随机改变你的内部数据。
这也是为什么最好尽量保持你的属性只读,如果可能你的对象是不可变的。
答案 1 :(得分:0)
完成后
var main = new Main { Property = 1 };
你有一个类型Main
的对象在内存中分配(让我们命名为Main1
),在某个内存地址X,变量main
指向该对象。 “点数”表示它实际存储该对象Main1
的地址,因此main
包含X
。
然后将Main1
的引用传递给Dependent
object
var dependent = new Dependent(main);
Dependent
对象也分配在内存中的某个位置,其中一个字段存储对Main1
对象的引用。所以dependent.Main
也存储了X。
当你这样做时
ChangeRef(ref main, new Main { Property = 5 });
您在内存地址Main5
的某处分配新对象Y
。现在,您可以更改变量main
指向的地址。在存储地址X
(Main1
的地址)之前,它现在存储地址Y
(Main5
的地址)。但dependent.Main
仍会存储地址X
,因为您没有以任何方式更改地址,因此它仍指向对象Main1
。