我的问题很简单,专门针对带有CLR的C#。
首先我们得到了代码片段1:
public void f(SomeClass sc)
{
anExistingInstance.FieldOfSomeClass = sc;
}
现在是代码段2:
public void f()
{
SomeClass sc = new SomeClass();
anExisitingInstance.FieldOfSomeClass = sc;
}
在代码1中,当调用f
并定义sc
的方法结束时,我猜测sc
已被释放,这就是anExisitingInstance.FieldOfSomeClass
不再存在的原因有效的。
我的问题是为什么在代码2中不会发生同样的事情,而是使用方法f
本身?为什么在f
完成后,anExisitingInstance.FieldOfSomeClass
仍然保持正确的值?
答案 0 :(得分:2)
您示例中唯一重要的实体是anExistingInstance
。我们不知道它的定义位置以及谁拥有对它的引用,但是此对象包含对SomeClass
实例的引用。 创建 SomeClass
实例的人并不重要,只是anExistingInstance
拥有对它的引用。其他一些类可能会引用anExistingInstane
,依此类推,直到你到达GC根目录。
只要您的SomeClass
实例链接回GC根目录,就不会进行垃圾回收。一旦此链中的任何链接不再链接到GC根(比方说,有人发布了对anExistingInstance
的引用,它引用的所有对象(未被其他东西引用)都有资格进行垃圾回收
答案 1 :(得分:1)
在代码1中,当调用f和定义的sc的方法结束时,我猜测sc被释放了,这就是为什么anExisitingInstance.FieldOfSomeClass不再有效。
没有。当anExistingInstance
超出范围时,则其所有字段也不再可访问(除非另一个对象引用)。因此,sc
仅在anExistingInstance
不在范围内时才有资格进行垃圾回收。
如果在父级/生根对象仍然在范围内时收集了对象,则代码中会抛出10000多倍NullReferenceException
。
我的问题是为什么在代码2中不会发生同样的事情,而是使用方法f本身?为什么当f完成时,anExisitingInstance.FieldOfSomeClass仍然保持正确的值?
它是一样的。即使在该方法中创建了sc
,它现在也以anExistingInstance
对象为根。一旦anExistingInstance
超出范围,sc
也有资格进行垃圾收集。
答案 2 :(得分:0)
我的问题是为什么在代码2中不会发生同样的事情,而是使用方法f本身?
因为包含方法f
的类尚未处理。请参阅第一种情况,其他人创建sc
以便它能够处置它 - 但在第二种情况下,您在方法中创建了sc
。它将保留在范围内,而创建它的类在范围内。
答案 3 :(得分:0)
Why when f is done, anExisitingInstance.FieldOfSomeClass still holds a correct value?
当没有对它的引用时,对象被垃圾收集。在这两种情况下,都有一个对象anExisitingInstance
,其中包含对SomeClass
的引用。并且在anExisitingInstance
gc'es时会被gc'ed。