Using a thread-safe dictionary in .NET C# Part 4: thread-safe insertlookups

In the previous post we looked at how the AddOrUpdate method worked. We saw that it was a very neat and thread-safe way to either insert a new key-value pair or update an existing one.

We’ve already seen a thread-safe method that helps you retrieve values by their keys in this post: TryGet. It returns true if the item could be retrieved. TryAdd on the other hand is used to insert a new key-value pair. It also returns true if the item could be inserted successfully. However, what do you do with the returned boolean values? Do you keep trying in some loop until it succeeds?

The GetOrAdd method combines the element retrieval and insertion in one operation. It accepts a key and a value and returns the value of the key-value pair. As its name implies it adds the provided key-value pair if there’s no element with that value. Also, it updates an existing element if it already exists by a given key. Alternatively it accepts a delegate – a lambda function – which calculates the value based on the key. That function is similar to the one we saw in the previous post on AddOrUpdate method which also accepted a delegate.

The AddOrGet delegate differs from the AddOrUpdate delegate in that its signature only accepts the key for a newly inserted key-value pair.

If there’s already a key-value pair with that key then the update parameter is ignored.

The following example demonstrates the GetOrAdd method in action:

public void RunGetOrAddSample()
{
	ConcurrentDictionary<string, int> movieCategoriesOnStock = new ConcurrentDictionary<string, int>();
	movieCategoriesOnStock.TryAdd("Romance", 12);
	movieCategoriesOnStock.TryAdd("Action", 9);
	movieCategoriesOnStock.TryAdd("Comedy", 20);
	Debug.WriteLine("Dictionary content before AddOrGet:");
	foreach (var kvp in movieCategoriesOnStock)
	{
		Debug.WriteLine(string.Format("{0}: {1}", kvp.Key, kvp.Value));
	}

	int zombie = movieCategoriesOnStock.GetOrAdd("Zombie", 10);
	Debug.WriteLine("Zombie: {0}", zombie);

	int action = movieCategoriesOnStock.GetOrAdd("Action", 234);
	Debug.WriteLine("Action: {0}", action);

	int scifi = movieCategoriesOnStock.GetOrAdd("Sci-fi", (key) => { return key.Length; });
	Debug.WriteLine("Sci-fi: {0}", scifi);

	int drama = movieCategoriesOnStock.GetOrAdd("Drama", (key) => { return CalculateNewValueFromKey(key); });
	Debug.WriteLine("Drama: {0}", drama);

	Debug.WriteLine("Dictionary content after GetOrAdd:");
	foreach (var kvp in movieCategoriesOnStock)
	{
		Debug.WriteLine(string.Format("{0}: {1}", kvp.Key, kvp.Value));
	}
}

private int CalculateNewValueFromKey(string key)
{
	return key.GetHashCode();
}

…and it gives the following output:

Dictionary content before AddOrGet:
Action: 9
Romance: 12
Comedy: 20
Zombie: 10
Action: 9
Sci-fi: 6
Drama: -1538741386
Dictionary content after GetOrAdd:
Action: 9
Romance: 12
Drama: -1538741386
Zombie: 10
Sci-fi: 6
Comedy: 20

View the list of posts on the Task Parallel Library here.

Advertisement

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

%d bloggers like this: