2015-04-03 33 views
4

我已经确定了以下难以理解的行为。将属性从实例外部设置为空

我假定您可以将对象A的属性设置为对象B,操作对象B并且将对对象A的属性进行更改(因为它是相同的对象)。我期待这个单元测试通过,但是在将B设置为null时,它在最后一行失败。为什么?

[TestMethod] 
    public void TestObject() 
    { 
     Child child = new Child(); 
     var parent = new Parent(child); 
     child.Name = "John"; 
     Assert.AreEqual(parent.Child.Name, "John"); 
     child = null; 
     Assert.IsNull(parent.Child); 
    } 

    public class Child 
    { 
     public string Name { get; set; } 
    } 

    public class Parent 
    { 
     public Child Child { get; set; } 

     public Parent(Child kid) 
     { 
      Child = kid; 
     } 
    } 
+0

“崩溃”并没有真正告诉我们任何事情。异常更有用。 – 2015-04-03 13:29:55

+1

将'child'设置为null只是设置局部变量'child'。 'parent.Child'仍然指向构造'parent'时分配给'child'的实例。 – 2015-04-03 13:31:13

+0

的确儿童被设置为空而不是parent.child。如果你将parent.child设置为null,它将按照你的意图工作。 – 2015-04-03 13:34:07

回答

13

此行

child = null; 

没有做什么,你认为它。它空值出来的参考Child对象,你TestObject()法保留,但对参考本Parent对象持相同Child对象没有影响:您分配child = null之前

Before the change

后分配child = null

After the change

这就是为什么

Assert.IsNull(parent.Child); 

失败:parent.Child引用是从您已经清零了child参考值不同。

在另一方面,如果你这样做child.Name = null然后parent.Child.Name将成为null还有:

child.Name = null; 
Assert.IsNull(parent.Child.Name); 
+0

我认为在这种情况下,一旦Parent对象被销毁,GC将只收集Child对象? – Keysharpener 2015-04-03 13:45:33

+0

@Keysharpener绝对! GC不会收集对象,直到最后一次到达对象的引用消失。如果将'parent'设置为'null',则引用'parent.Child'将变得无法到达,因此'Parent'和'Child'都将符合GC的条件。 – dasblinkenlight 2015-04-03 13:47:38

3

Child属性是在内存中的实际子对象的引用。你的本地变量“child”是对同一个对象的另一个不同的引用。当您将您的本地孩子设置为空时,它不会触及父母对其的引用。 如果您在任一引用上设置了Name属性,那么这将更改实际对象,并且您会看到它通过两个引用都反映出来。

5

你在引用的工作方式上犯了一个错误。当您将Child对象传递给Parent对象时,您正在传递对该对象的引用。这意味着当您更改Child对象的名称时,Parent.child会看到这些更改,因为它是对同一对象的引用。当时,您的child变量和Parent.child属性指向相同的引用,这就是设置名称以您期望的方式更改它的原因。但是,如果将child设置为null,则您正在更改它的引用,它现在指向没有对象(null),但是您还没有做任何操作Parent.child指向的引用,它仍然具有对原始对象的引用,所以它不会更改为空,因为您在设置child = null时所做的全部操作都是删除对象的引用,而不是以任何方式更改对象。这是一样的,如果你有

Child child2 = child; 
child = null; 

在这种情况下child2不会被设置为null,因为child2所指向的对象是原child参考,你所做的一切是删除使用的参考,而不是自己操纵参考。