Ayende @ Rahien

It's a girl

I love ConcurrentDictionary!

Not just because it is concurrent, because of this wonderful method:

public class Storage : IStorage
{
    private readonly ConcurrentDictionary<Guid, ConcurrentDictionary<int, List<object>>> values =
        new ConcurrentDictionary<Guid, ConcurrentDictionary<int, List<object>>>();

    public void Store(Guid taskId, int level, object value)
    {
        values.GetOrAdd(taskId, guid => new ConcurrentDictionary<int, List<object>>())
            .GetOrAdd(level, i => new List<object>())
            .Add(value);
    }
}

Doing this with Dictionary is always a pain, but this is an extremely natural way of doing things.

Tags:

Posted By: Ayende Rahien

Published at

Originally posted at

Comments

Tommy Carlier
03/22/2010 10:31 AM by
Tommy Carlier

That's awesome. You could do this with regular dictionaries, by adding an extension method to IDictionary <tkey,> , like this:

static TValue GetOrAdd <tkey,> (this IDictionary <tkey,> collection, TKey key, Func <tkey,> generator)

{

TValue value;

if (!collection.TryGetValue(key, out value))

collection.Add(key, value = generator(key));

return value;

}

Tommy Carlier
03/22/2010 10:33 AM by
Tommy Carlier

Your commenting system apparently doesn't escape less-than and greater-than. Second attempt:

static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> collection, TKey key, Func<TKey, TValue> generator)

{

TValue value;

if (!collection.TryGetValue(key, out value))

collection.Add(key, value = generator(key));

return value;

}

Torkel
03/22/2010 11:19 AM by
Torkel

That is a pretty useful function!

Dam, why did I not think of writing one like that. I do have a similar one I use for caches.

For example:

return cache.GetWithAdd("admembers", () => GetADMemberListRemote());

Paul Hatcher
03/22/2010 11:24 AM by
Paul Hatcher

You'd need some form of locking to make it thread safe, e.g.

TValue value;

lock (collection)

{

if (!collection.TryGetValue(key, out value))

collection.Add(key, value = generator(key));

}

return value;

And of course this doesn't preclude someone bypassing the lock by directly doing collection.Add

Robert Byrne
03/22/2010 11:30 AM by
Robert Byrne

Yea some of the first extension methods I wrote were to deal with dictionaries. If theres nothing special about the way you construct the value, you can simplify slightly:

public static TValue GetOrAddDefaultValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key) {

if (dictionary == null) return default(TValue);


TValue value = default(TValue);

bool exists = dictionary.TryGetValue(key, out value);


if (!exists) {

    if (typeof(TValue).IsValueType) {

        dictionary[key] = value;

    }

    else {

        value = Activator.CreateInstance<TValue>();

        dictionary[key] = value;

    }

}


return value;

}

configurator
03/22/2010 12:25 PM by
configurator

Shouldn't you use some concurrent datatype for the list as well?

tobi
03/22/2010 01:43 PM by
tobi

Although it is beside your point you use a single dictionary with a tuple as the key.

Comments have been closed on this topic.