C# 在用作返回值的函数内部声明的对象会发生什么情况?为什么不';他们不会在返回时被取消分配吗?

C# 在用作返回值的函数内部声明的对象会发生什么情况?为什么不';他们不会在返回时被取消分配吗?,c#,.net,oop,garbage-collection,allocation,C#,.net,Oop,Garbage Collection,Allocation,假设您有以下内容:(遗漏了样板代码) 至少在C#中,当您尝试使用输出时,程序不会崩溃,即使它指向foo中声明的相同对象。为什么没有立即取消分配? 如果这是一种处理对象返回值的糟糕方法,那么有没有更好的方法来处理它?引用传递。对象是引用类型,这意味着对其所做的每一次更改(包括分配)都将保留在声明此对象的块上 如果您使用了一些C/C++,那么引用在某种程度上是自动管理的指针 这是一种不错的做法,但要小心。当您返回引用并在以后分配它时,如果您碰巧之前已经分配了它,那么您将丢失以前的版本。同样,如果您使

假设您有以下内容:(遗漏了样板代码)


至少在C#中,当您尝试使用输出时,程序不会崩溃,即使它指向foo中声明的相同对象。为什么没有立即取消分配?
如果这是一种处理对象返回值的糟糕方法,那么有没有更好的方法来处理它?

引用传递。对象是引用类型,这意味着对其所做的每一次更改(包括分配)都将保留在声明此对象的块上

如果您使用了一些C/C++,那么引用在某种程度上是自动管理的指针


这是一种不错的做法,但要小心。当您返回引用并在以后分配它时,如果您碰巧之前已经分配了它,那么您将丢失以前的版本。同样,如果您使用了一些C,这就像将指针指向第二个分配的内存部分,留下第一个(在前面的示例中)。GC将只收集(如果它选择)没有可访问引用的对象。在您的示例中:

static object foo()
{
    object test = new object();
    return test;
}

object output = foo();  
foo
返回时,
test
引用的实例也被
output
引用。因此,即使
test
不再是可访问的引用,
output
仍然是,因此,它“指向”的实例不是收集的候选实例

以下示例与此完全不同:

static object foo()
{
    object test = new object();
    return test;
}

foo();
在这里,
test
引用的实例在
foo
返回时(甚至在返回之前,但让我们忽略这些优化),是收集的有效候选对象,因为一旦
foo
返回,就没有可访问的对象引用

请注意,我使用的是可访问引用。对象可能有引用它的有效引用,但如果包含该引用的对象也是集合的候选对象,则该对象仍然是集合的候选对象。
GC
对于这类循环足够聪明:

class A { public B b; }
class B { public A a; }

void Foo()
{
    A a = new A();
    B b = new B();
    a.B = b;
    b.A = a;
}

Foo(); //both a and b are elegible for collection once Foo exists.

“为什么它没有立即被取消分配?”因为垃圾收集,我们正在传递引用。C#中的爱永远不必说你完成了。“C#中的爱永远不必说你完成了。”-这很深@jeroenmoster:D Ken:通过将引用指定给
输出
,有一个对函数内部创建的对象的强引用。这就是GC不会收集它的原因。为什么这是“处理对象返回值的糟糕方法”?否则您将如何返回引用类型?将其转过来,为什么程序会崩溃?你在这里想干什么不是很清楚吗?您是否希望程序崩溃,因为您没有明确告诉它制作一个适合函数外部访问的副本?您想确切地知道堆栈上的内容以及每个点上的堆上的内容吗?如果你说“是的”,你可以拥有一份出色的C程序员职业——但你(大部分)在编写C#时不需要背负这种精神包袱。
class A { public B b; }
class B { public A a; }

void Foo()
{
    A a = new A();
    B b = new B();
    a.B = b;
    b.A = a;
}

Foo(); //both a and b are elegible for collection once Foo exists.