Understanding ConditionalWeakTable

cm007 picture cm007 · Aug 27, 2013 · Viewed 12.6k times · Source

I am trying to understand ConditionalWeakTable. What is the difference between

class ClassA
{
    static readonly ConditionalWeakTable<ClassA, OtherClass> OtherClassTable
        = new ConditionalWeakTable<ClassA, OtherClass>();
}

and

class ClassB
{
    OtherClass otherClass;
}

? What would be the pros and cons of using ClassA or ClassB to reference a nullable field?

Answer

jwaliszko picture jwaliszko · Sep 4, 2013

I don't exactly get what you're asking about, I assume though you're asking whether you should use property inside your type or ConditionalWeakTable, to which you can attach such a property for that particular type instance. If so, you could alternatively ask whether you should use property alone versus dictionary, which could contain this property under specific key (which will be your particular type instance). Unless you need such a dictionary, it's pretty nonsense.

Understanding of ConditionalWeakTable<TKey, TValue>:

What ConditionalWeakTable actually do is, it allows you to attach additional information to existing, managed, non-dynamic CLR objects. Essentially it can be understood just as a dictionary, where the keys are weakly referenced, so a value is kept alive as long as the key is alive. More information can be found on MSDN.

So, you should ask yourself what are your needs. Assuming your types are instantiated:

var classA = ClassA(); 
var classB = ClassB(); 
var other = OtherClass();

do you want to use the property binded to such instances in this manner:

/* set */
var other = new OtherClass();        
ClassA.OtherClassTable.Add(classA, other);
/* get */
OtherClass data = null;
var result = ClassA.OtherClassTable.TryGetValue(classA, out data);

instead of this one below?

/* set */
classB.OtherClass = other;
/* get */
var result = classB.OtherClass;

Unless have particular needs, the answer seems to be pretty obvious. There are of course further issues here:

What is weak reference and why would you want to use it?

This MSDN article shortly explains the topic. It basically says weak references do not extend the lifetime of the object, by allowing it to be garbage collected, once such an object can still be reached by the application code. Weak references can be useful for pointing to objects which should be available for GC if they are not actively in use. However, if the program uses large number of small objects, weak references can negatively affect memory usage. Threads like this and this should also clarify some remaining doubts.

If you're looking for an example, when you could use ConditionalWeakTable<TKey, TValue> over standard Dictionary<TKey, TValue>, imagine the following case. You'd like to bind a dictionary of properties to an instance at runtime, but at the same time do not want to prevent them from being collected if you've stopped actively using them. Unfortunately in standard approach it's impossible - GC is blocked because dictionary still holds a strong references to them, like this:

var x = new object();
x.Props().Y = "hello";

static class ExpandoExtensions 
{
    private static IDictionary<object, dynamic> props = 
        new Dictionary<object, dynamic>();
    public static dynamic Props(this object key)
    { 
        dynamic o;
        if (!props.TryGetValue(key, out o)){
            o = new ExpandoObject();
            props[key] = o;
        }
        return o;       
    } 
}

Of course you can always take down them manually, but isn't this approach shown below simpler?

static class ExpandoExtensions
{
    private static readonly ConditionalWeakTable<object, ExpandoObject> props =
        new ConditionalWeakTable<object, ExpandoObject>();

    public static dynamic Props(this object key)
    { 
        return props.GetOrCreateValue(key);       
    } 
}

At the same time (MSDN)

avoid using weak references as an automatic solution to memory management problems. Instead, develop an effective caching policy for handling your application's objects.

These extension methods shown above are taken from this thread.