Search code examples
c#.netmemory-managementweak-references

Is it possible to use ConditionalWeakTable with a Tuple key (or a key comprised of multiple references)?


I am a big fan of the ConditionalWeakTable<TKey,TValue>. It's really quite great. It essentially allows you associate/attach/pair one reference to another reference, all while being thread-safe.

It answers a lot of questions/problems for me. Unfortunately, I seem to have a problem I continue to run into, and have not been able to find a good answer to it.

Let's say I have a method (denoted by a test method below) where I am using a ConditionalWeakTable, but instead of using a single reference for the key, I instead need to combine two items and make that the key. This is shown below by way of a Key object (which is simply an extended Tuple for demonstration purposes and terseness):

[Fact]
public void TupleKey()
{
    var first = new object();
    var table = new ConditionalWeakTable<Key, object>();
    var context = table.GetValue( new Key( first, new object() ), key => new object() );

    // .. table has one entry here.

    GC.Collect();
    GC.WaitForPendingFinalizers();

    Debugger.Break(); // Table is empty here.
            
}

class Key : Tuple<object, object>
{
    public Key( object item1, object item2 ) : base( item1, item2 ) {}
}

When the Debugger.Break is called, the ConditionalWeakTable is empty, even though there is an active reference to one of the parts of the Key in the test method. This makes sense as the reference to the Key is nowhere to be found in the test.

However, since there is one active reference to one of the parts of the Key object, I would like the entry in the ConditionalWeakTable to also remain active, and stay active until all of its children/inner references are claimed.

(In thinking about this and possible solutions, it would awesome if there was a WeakHashSet that could somehow be used as the key to a Dictionary<>, but from some searching, it does not appear that a WeakHashSet exists in .NET.)

Hopefully this outlines my dilemma. I am basically wanting to use a ConditionalWeakTable (or some equivalent) to store an associated a value (as an key/value entry), but rather than using one (weak) reference as the key to the entry, I would like to use two (or more).

Is what I am looking to achieve possible (without having to write a significant amount of custom code, that is)?


Solution

  • This question is related to this question and I have finally found an answer that solves this one and that one was well. You can read the answer for more details.

    In regards to this question. It comes down to a more refined/clever/intelligent use of the "key" to use for a ConditionalWeakTable. In my case, I was wrestling with three parts of a key (instance, method, and arguments). I managed to combine the first two by use of a Delegate (which is basically a reference tuple to the instance and method) and then pair that with a Dictionary<object[], object> that uses a StructuralEqualityComparer. Whalah. Problem solved.