Michał Sakowicz avatar.

Michał Sakowicz

Software craftsman. Hooked on distributed systems. Proponent of simplicity. Bigger picture advocate.

GitHub  |  LinkedIn  |  Twitter  |  RSS  |  Contact

ConditionalWeakTable Class

Posted by Michał Sakowicz on 29 March, 2018

ConditionalWeakTable is not new but unknown to me piece of functionality offered by C#. It was introduced in C# 4 and allows thread-safe, association of additional data with existing class. There is no need to modify class implementation, it can be sealed or supplied by 3rd party library. Let’s consider following example:

using System.Runtime.CompilerServices;

public sealed class Data
{
    public int Value1 { get; set; }
}

public class ExtraValues
{
    public int Value2 { get; set; }
}

public static class ExtraValuesProvider
{
    private static ConditionalWeakTable<Data, ExtraValues> _table = new ConditionalWeakTable<Data, ExtraValues>();

    public static void SetValue2(this Data data, int value)
    {
        _table.GetOrCreateValue(data).Value2 = value;
    }

    public static int GetValue2(this Data data)
    {
        return _table.GetOrCreateValue(data).Value2;
    }

    public static void PrintValues(this Data data)
    {
        Console.WriteLine($"Value1: {data.Value1}, Value2: {data.GetValue2()}");
    }
} 

Objects above:

  • Data - class we want to extend.
  • ExtraValues - additional information we want to store.
  • ExtraValueProvider - object that facilitates linking Data with ExtraValues and provides extension methods for data manipulation.

We can use it like this:

static void Main(string[] args)
{
    var data = new Data();
    data.Value1 = 1;
    data.SetValue2(2);

    int i = data.GetValue2();

    data.PrintValues();
}

ConditionalWeakTable is using WeakReference to link classes so when the object instance is garbage collected, any attached values are automatically cleaned up as well.

Extra points to note:

  • In the code snippet we have method PrintValues - extension method ToString() would fit here nicer - unfortunately it’s not possible - as instance methods have precedence over extension methods.
  • It would also be cleaner to replace GetValue2 and SetValue2 methods with property - as above currently it’s not possible to create extension properties.
  • Mixin - new term for me - describing class that contains methods for use by other classes without using inheritance. In above case I believe ExtraValues and ExtraValuesProvider can be called a mixin.