C# 垃圾回收器复活导致的空引用异常

4

我有这段代码(摘自一个非常好的友好网站)

public class B
{
    static public A IntA;
}

public class A
{
    private int x;

    public A(int num)
    {
        x = num;
    }

    public void Print()
    {
        Console.WriteLine("Value : {0}", x);
    }

    ~A()
    {
        B.IntA = this;
    }
}

class RessurectionExample
{
    // Ressurection
    static void Main()
    {
        // Create A instance and print its value
        A a = new A(50);
        a.Print();

        // Strand the A object (have nothing point to it)
        a = null;

        // Activate the garbage collector
        GC.Collect();

        // Print A's value again
        B.IntA.Print();
    }
}

它创建一个带有值50的A实例,打印它,通过将唯一引用设置为null来阻止创建的对象,激活它的Dtor并在保存到B之后再次打印它。

现在,奇怪的是,在调试时,当光标指向最后一行(B.IntA.Print())时,静态A成员的值为null,在按下F10后,我会得到一个NullReferenceException,但静态A成员的值更改为应该是什么。

有人能解释这个现象吗?

1个回答

7
您需要调用 GC.WaitForPendingFinalizers 方法。如果不这样做,您的析构函数实际上不会按顺序被调用。
static void Main()
{
    // Create A instance and print its value
    A a = new A(50);
    a.Print();

    // Strand the A object (have nothing point to it)
    a = null;

    // Activate the garbage collector
    GC.Collect();

    // Add this to wait for the destructor to finish
    GC.WaitForPendingFinalizers();

    // Print A's value again
    B.IntA.Print();
}

谢谢,我只是假设提供这段代码的网站它能够正常工作。但我猜它是随机的,并且可能只在特定条件下起作用。 - user779444
1
具有讽刺意味的是,在此之前它能够正常运行的可能性非常小。 - Reed Copsey
如果你能回答最后一个问题——复活有什么用?什么时候会有人想要使用它? - user779444
通常情况下,你应该尽可能避免使用它。这不是你通常想要故意使用的东西。这更多是为了展示你可以这样做,但并不一定是个好主意。 - Reed Copsey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接