C# деструктор не вызывается даже после области кода + G C? - PullRequest
2 голосов
/ 22 января 2020

У меня есть простой тестовый код в Nunit +. net core 2.0 под VS2019:

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, и деструкторы вызываются сразу после Тестовое задание(). Но вы можете видеть, что "t" находится в блоке кода и недопустимо после блока кода, и я также вызывал

System.GC.Collect();

перед моим "Утверждением".

Почему деструктор не звонил даже после G C? Как исправить мой код, чтобы пройти тест?

Большое спасибо.

Ответы [ 2 ]

1 голос
/ 19 февраля 2020

Используйте , используя оператор и 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);
    }
}

Вы можете позвонить Система .G C .Collect () но это не имеет значения. Деструктор не будет вызван немедленно, как вы ожидаете. (В приведенном выше коде вам не нужно System.G C .Collect () )

enter image description here

Мне странно, почему Microsoft не делает это более понятным, вместо старого определения «Принудительная немедленная сборка мусора для всех поколений». , что заставляет разработчиков думать, что они должны ожидать немедленного результата и G C .Collect () должен дождаться завершения сбора мусора, прежде чем он вернется?!

G C .Collect Method (System) - Microsoft Docs

Еще более странным для меня является то, что код, который они приводят в качестве примера для использования G C .Collect ( ) не работают, как они утверждают, по той же причине. Вы можете попробовать себя, прокомментировав G C .Collect (); line. Я не знаю, может быть, они просто не обновляют свои документы так часто. Может быть, раньше была другая ситуация с G C .Collect () ?! G C .CollectRequest () будет более подходящим названием для этой функции, если вы спросите меня.

Strange example code on Microsoft page for GC.Collect()

Ps Я новичок в C#, поэтому, пожалуйста, извините, если я говорю вещи, которые не до конца понимают, или я что-то не так в коде я пишу.

0 голосов
/ 26 января 2020

Вызов GC.WaitForPendingFinalizers() после GC.Collect()

Финализаторы (не деструкторы) работают как фоновые задачи асинхронно, поэтому после вызова GC.Collect() и достижения оператора утверждения финализаторы не гарантированно завершатся.

...