当前位置: 首页 > 知识库问答 >
问题:

C#析构函数即使在代码范围GC之后也没有调用?[重复]

鄂育
2023-03-14

我有一个简单的Nunit测试代码。VS2019下的net core 2.0:

public class Tests
{
    public static int i = 0;
    class First
    {
        ~First()
        {
            i += 1;
            Console.WriteLine("First's destructor is called.");
        }
    }

    class Second : First
    {
        ~Second() { i += 10; Console.WriteLine("Second's destructor is called."); }
    }

    class Third : Second
    {
        ~Third() { i += 100; Console.WriteLine("Third's destructor is called."); }
    }
    [Test]
    public static void Test()
    {
        {
            Third t = new Third();
        }
        Thread.Sleep(1000);
        System.GC.Collect();
        Assert.AreEqual(111, i);
    }
}

它总是失败,而我最终发现i=0,析构函数在Test()之后被调用。但是你可以看到“t”在一个代码块中,在代码块之后是无效的,我也打了电话

System.GC.Collect();

在我的“断言”之前。

为什么即使在GC之后也不调用析构函数?如何修复代码以使测试通过?

谢谢。

共有2个答案

宇文和同
2023-03-14

在GC. Collect()之后调用GC. WaitForPendingFinalizers()

终结器(不是析构函数)作为后台任务异步运行,因此在调用GC之后。Collect()并到达断言语句。终结器不保证已完成。

鞠修雅
2023-03-14

使用使用语句和IDisposable接口代替析构函数;

 public class Tests
{
    public static int i = 0;
    class First : IDisposable
    {
        public virtual void Dispose()
        {
            i += 1; Console.WriteLine("First's Dispose is called.");
        }
    }

    class Second : First
    {
        public override void Dispose()
        {
            i += 10; Console.WriteLine("Second's Dispose is called.");
            base.Dispose();
        }
    }

    class Third : Second
    {
        public override void Dispose()
        {
            i += 100; Console.WriteLine("Third's Dispose is called.");
            base.Dispose();
        }
    }
    public static void Test()
    {
        using (Third t = new Third()) {
            Console.WriteLine("Now everything will be ok, after leaving this block");
            Console.WriteLine("t object will be dispose");
        }
        Thread.Sleep(1000);
        System.GC.Collect();
        Assert.AreEqual(111, i);
    }
}

你可以打电话给系统。收集(),但这并不重要。析构函数不会像您期望的那样立即被调用。(在上面的代码中,你不需要System.收集())

我感到奇怪的是,为什么微软没有更清楚地说明这一点,而不是旧的定义“强制所有代人立即进行垃圾收集”这使得开发人员认为他们应该期待立即的结果和GC。Collect()应该等待垃圾收集完成后再返回?!

GC。收集方法(系统)-Microsoft文档

对我来说更奇怪的是,他们给出的代码作为使用GC的示例。出于同样的原因,Collect()不能像他们声称的那样工作。您可以通过评论GC来尝试自己。收集();线我不知道,也许他们只是不经常更新他们的文档。也许GC之前的情况有所不同。收集()?!GC。如果你问我的话,CollectRequest()将是这个函数更合适的名称。

P. s.我是C#的新手,所以请原谅我,如果我在写的代码中说一些不完全理解的事情或者我错了的话。

 类似资料:
  • 更新1:根据建议添加了打印“this”。 更新2:拆分成几个文件,尝试阻止gcc优化。 更新3:记录复制构造函数并输入添加函数。 更新4:在main中添加了Clang和第二个cout的输出。 我希望参数析构函数作为函数中的最后一条语句被调用。从今以后,我希望下面的代码能够提供以下输出。 使用MSVC(Visual Studio)时,输出与预期的一样。但GCC(4.8.2-19ubuntu1)输出以

  • 问题内容: 我有一个C函数,我想从C 调用。我无法使用“ ”这样的方法,因为C函数无法使用g 进行编译。但是使用gcc可以很好地编译。有什么想法如何从C ++调用函数吗? 问题答案: 像这样编译C代码: 然后是这样的C ++代码: 然后使用C ++链接器将它们链接在一起: 当您包含C函数的声明时,还必须告诉C ++编译器C头即将到来。因此开始于: 应该包含以下内容: (在此示例中,我使用了gcc,

  • 问题内容: 我正在开发一个指令,该指令根据在模板中定义的click事件(ng- click)来显示和隐藏其内容。在某些使用该指令的视图上,我希望能够知道该指令当前是显示还是隐藏其内容,因此我可以响应DOM更改。该指令具有单独的作用域,当该指令被“切换”时,我试图通知父作用域。我正在尝试通过将回调函数传递给使用该指令的指令来实现此目的,该指令可以在指令的状态更改(即隐藏或显示)时调用 我不确定该指令

  • 问题内容: 如何从其父范围调用在子范围中定义的方法? http://jsfiddle.net/wUPdW/ 问题答案: 您可以从父母到孩子使用: 工作jsfiddle:http : //jsfiddle.net/wUPdW/2/ 更新 :还有另一个版本,耦合性更低,更易于测试: jsfiddle:http : //jsfiddle.net/uypo360u/

  • 我在R中查看cov的source_code,遇到了一段我不太理解的代码。 协方差的数学定义在这里。