Ho avuto la necessità di scrivere un oggetto che gestisca in modo deterministico il ciclo di vita un oggetto aggregato, che deve essere finalizzato in modo opportuno.

Per raggiungere questo obiettivo ho utilizzato il pattern IDisposable (vedi Implement IDisposable Correctly), poi ho scritto un test per verificare che l'oggetto quando finalizzato attraverso IDisposable (cioè quando usato in un blocco using(...) { }), finalizzasse a sua volta correttamente l'oggetto aggregato.

Volevo però verificare anche che la stessa operazione di finilazzazione avvenisse quando l'oggetto è rilasciato dal Garbage Collector, così ho dovuto trovare un metodo per forzare in modo deterministico e sincrono la finalizzazione degli oggetti nel GC. Ho scritto quindi una semplice funzione che effettua questa operazione chiamando in modo opportuno metodi statici della classe GC.

    public static class UtilsGarbageCollector

    {

        public static void ForceCompleteCollectAndWait()

        {

            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);

            GC.WaitForPendingFinalizers();

        }

    }

Ho scritto poi un test specifico per verificare le aspettive di questa funzione.

    [TestClass]

    public class TestFullSyncronizedCollect

    {

        [TestMethod]

        public void ShouldDeterministicCollectAllNotReferencedObject()

        {

            for (int i = 0; i < 100; i++)

            {

                new ClassA();

                new ClassB();

                new ClassC();

                new ClassD();

                new ClassE();

            }

 

            UtilsGarbageCollector.ForceCompleteCollectAndWait();

 

            Assert.AreEqual(0, BaseInstanceCounter.ClassInstance);

        }

    }

Dove le classi ClasseA...E sono sottoclassi di una particolare classe che conta le instanze "vive e non finalizzate".

    public class BaseInstanceCounter

    {

        public static int ClassInstance = 0;

 

        public BaseInstanceCounter()

        {

            ClassInstance++;

        }

 

        ~BaseInstanceCounter()

        {

            ClassInstance--;

        }

    }

 

    public class ClassA : BaseInstanceCounter { }

    public class ClassB : BaseInstanceCounter { }

    public class ClassC : BaseInstanceCounter { }

    public class ClassD : BaseInstanceCounter { }

    public class ClassE : BaseInstanceCounter { }

Se commentate nel test la chiamata al metodo UtilsGarbageCollector.ForceCompleteCollectAndWait(); questo non passa. (...è corretto dire quasi sempre non essendo deterministico il momento di finalizzazione degli oggetti da parte del GC)