不能在方法中设置对象为空
本文关键字:对象 设置 方法 不能 | 更新日期: 2023-09-27 17:51:24
在下面的代码中,我试图在测试方法中将节点设置为null。当我这样做时,节点仅在方法范围内变为Null,但'parent'不会变为Null。我的理解是对象作为引用传递给方法,可以在方法内部直接操作。我认为我的概念理解有问题。你能解释一下为什么将节点赋值为空并不会将父节点赋值为空吗?
class Program
{
static void Main(string[] args)
{
Node parent = new Node();
parent.key = 50;
parent.left = new Node();
Test.test(parent);
}
}
class Test
{
public static void test(Node node)
{
node.key = 1111;
node = null;
}
}
class Node
{
public object key { get; set; }
public Node left = null;
public Node right = null;
}
您实际上并没有通过引用将parent
传递给node
。这意味着在test
函数中将parent
的值复制到node
。在本例中,该值只是指向一个Node
对象。
node.key = 1111
的工作方式与您预期的一样,因为它使用该值访问parent
也指向的同一个对象。即node
和parent
都包含指向内存中相同位置的值。因此,两者都可以观察到修改。
然而,当你说node = null
时,你正在为test
函数中的node
变量分配一个新值。这意味着你将指针作为特定变量的值存储为null
,这不会修改parent
的值-它仍然指向Node
对象。
请注意我的业余ASCII艺术,但我认为它有点像这样:
Test.test(parent);
<node object>
^ ^
. .
. .
. .
+------.----+ . +-----------+
| . | . |
| . | (-> copied to) | . |
| parent | | node |
+-----------+ +-----------+
Program.Main scope Test.test scope
node = null;
<node object>
^
.
.
.
+------.----+ +-----------+
| . | | |
| . | | |
| parent | | node=null |
+-----------+ +-----------+
Program.Main scope Test.test scope
然而,如果你碰巧使用public static void test(ref Node node)
,你可以这样想:
Test.test(parent);
<node object>
^
.
.
.
+------.----+ +-----------+
| parent <============================ node |
| | | |
| | | |
+-----------+ +-----------+
Program.Main scope Test.test scope
node = null;
<node object>
Lonely
+-----------+ +-----------+
| parent <============================ node |
| = | | |
| null | | |
+-----------+ +-----------+
Program.Main scope Test.test scope
这是因为参数是按值传递的,所以在您的测试方法中,已经创建了父变量的副本,您只是将变量的副本设置为null。尽管您仍然可以操作对象,因为复制变量指向堆中的对象。
class Program
{
static void Main(string[] args)
{
Foo foo = new Foo();
SetNull(foo);
Console.WriteLine(foo.ID);// print 2
}
private static void SetNull(Foo foo)
{
foo.ID = 2;
foo = null;
}
}
class Foo
{
public int ID { get; set; }
}
使用ref
关键词:
public static void Test(ref Node node) {
node = null;
}
// Usage
Node parent = ...
Test( ref parent );
Assert( parent == null );
在这里用不同的变量名重写这个方法,以供示例使用:
public static void test(Node PassedNode)
{
PassedNode.key = 1111;
PassedNode = null;
}
test
方法中的 PassedNode
指向最初传入的Node parent = new Node();
对象,因此当您在test
方法中修改PassedNode
的属性值时,这些更改将影响Main方法中的对象,因为只有一个对象。当您编写PassedNode = null
时,test
方法中的PassedNode
不再指向原始对象,这就是所发生的一切:对象本身仍然存在。如果要清除原始引用,则需要在调用方法中执行此操作。