不能在方法中设置对象为空

本文关键字:对象 设置 方法 不能 | 更新日期: 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也指向的同一个对象。即nodeparent都包含指向内存中相同位置的值。因此,两者都可以观察到修改。

然而,当你说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不再指向原始对象,这就是所发生的一切:对象本身仍然存在。如果要清除原始引用,则需要在调用方法中执行此操作。