The ConditionalWeakTable in .NET

The ConditionalWeakTable class exists in the System.Runtime.CompilerServices namespace and as its namespace suggests is used in compilation processes.

The class allows a key-value pair to be stored (using its Add method), once the key object no longer has any references outside of the ConditionalWeakTable the key can be destroyed during garbage collection as the key is held as a weak reference inside the table, as opposed to a usual strong reference. At this point the key object can be garbage collected. Also at this point, if the value object also has no other references, it too can be collected. Or too quote MSDN: “It does not persist keys. That is, a key is not kept alive only because it is a member of the collection”.

The following code shows a console application followed by its output:

using System;
using System.Runtime.CompilerServices;

namespace ConditionalWeakTableExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var cwt = new ConditionalWeakTable<SomeKeyClass, SomeValueClass>();

            Console.WriteLine("Creating new instance of SomeKeyClass called key1");
            var key1 = new SomeKeyClass();

            Console.WriteLine("Creating new instance of SomeValueClass called value1");
            var value1 = new SomeValueClass();

            Console.WriteLine("Creating variable anotherReferenceToKey1 referencing key1");
            var anotherReferenceToKey1 = key1;

            Console.WriteLine("Adding key1, value1");
            cwt.Add(key1, value1);




            Console.WriteLine("Press a key to set key1 to null");
            Console.ReadLine();
            key1 = null;
            Console.WriteLine("key1 to null");

            ForceGc();




            Console.WriteLine("Press a key to set anotherReferenceToKey1 to null");
            Console.ReadLine();
            anotherReferenceToKey1 = null;
            Console.WriteLine("anotherReferenceToKey1 to null");

            ForceGc();            




            Console.WriteLine("End of program - press any key to exit");
            Console.ReadLine();
        }


        private static void ForceGc()
        {
            Console.WriteLine("Forcing garbage collection and waiting for finalizers");
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }


    class SomeKeyClass
    {
        ~SomeKeyClass()
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("****** SomeKeyClass Destroyed");
            Console.ResetColor();
        }        
    }

    class SomeValueClass
    {
        ~SomeValueClass()
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("****** SomeValueClass Destroyed");
            Console.ResetColor();
        }
    }
}

image

 

So here, even though the cwt contains an entry using key1, it is held in a weak way so it will not prevent garbage collection.

Also notice in this example, the value object has not been destroyed as we still have a reference to it in the variable value1.

If we change the code to also set value1 to null, when the Garbage Collector runs it will destroy the key object as before, but now there are also no references to the value object, so it too can be destroyed:

static void Main(string[] args)
{
    var cwt = new ConditionalWeakTable<SomeKeyClass, SomeValueClass>();

    Console.WriteLine("Creating new instance of SomeKeyClass called key1");
    var key1 = new SomeKeyClass();

    Console.WriteLine("Creating new instance of SomeValueClass called value1");
    var value1 = new SomeValueClass();

    Console.WriteLine("Creating variable anotherReferenceToKey1 referencing key1");
    var anotherReferenceToKey1 = key1;

    Console.WriteLine("Adding key1, value1");
    cwt.Add(key1, value1);




    Console.WriteLine("Press a key to set key1 to null");
    Console.ReadLine();
    key1 = null;
    Console.WriteLine("key1 to null");

    ForceGc();




    Console.WriteLine("Press a key to set anotherReferenceToKey1, value1 to null");
    Console.ReadLine();
    anotherReferenceToKey1 = null;
    value1 = null;
    Console.WriteLine("anotherReferenceToKey1 & value1 to null");

    ForceGc();            




    Console.WriteLine("End of program - press any key to exit");
    Console.ReadLine();
}

 

image

 

So even though this is not a class we’d use in everyday coding, it’s one of the many interesting things in .NET that are hidden away in namespaces we don’t usually use. It also should be noted that it doesn’t really behave as a “normal” dictionary, for example it doesn’t contain GetEnumerator method.

If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.

SHARE:

Comments (3) -

  • Eric Potter

    12/4/2014 1:54:51 AM | Reply

    This is fascinating. I'd love to see how it is implemented. I don't see it in the CoreFX repo on github. Do you know if I am looking in the wrong place or have they simple not posted this library yet?

  • Jason

    12/4/2014 9:41:54 AM | Reply

    Good question Eric, not sure about the CoreFX bit, but you can try clicking on ConditionalWeakTable  in code in Visual Studio and hitting F12

Pingbacks and trackbacks (5)+

Add comment

Loading