«

»

Jul 20

C# Alternative to a Type Dictionary

Somewhat recently, I needed a dictionary whose index was the entry’s type. The obvious way to go about this of course was to simply create a dictionary whose index was the entry’s type, like so:

ConcurrentDictionary<RuntimeTypeHandle, object> _typeDictionary;

There is a really cool, and much faster, alternative though – which was brought to my attention by one of the geniuses (Wil Bennett) I’m fortunate enough to work with every day. You can leverage C# Generics to accomplish exactly what the dictionary would. First, create this simple class that will function essentially like the type-indexed dictionary entry. I’m going to use an integer to function as the dictionary entry’s value in this example; you’d replace this with whatever value you’re interested in indexing.

private class Context<T>
{
       public static volatile int Value = 0;
}

Then, we need a method that will utilize our new class – something simple, just to show off how much faster it is relative to just using a Dictionary.

public void TimeClass<T>(int iterations)
{
       int value = 0;

       var watch = Stopwatch.StartNew();
       Context<int>.Value = 0;

       for (int i = 0; i < iterations; i++)
       {
              ++Context<T>.Value;
       }

       watch.Stop();
       value = Context<int>.Value;

       if (iterations <= 10)
              return;

       Console.WriteLine("Class        : Iterations: {0:N0}, Elapsed: {1}, Value: {2:N0}",
              iterations, watch.Elapsed, value);
}

Now, to test this, we can add a couple of additional methods that use the more conventional approaches to this problem.

public void TimeDictionary<T>(int iterations)
{
       var dict = new Dictionary<Type, int>();
       int value = 0;

       var watch = Stopwatch.StartNew();
       var type = typeof(T);

       for (int i = 0; i < iterations; i++)
       {
              if (!dict.TryGetValue(type, out value))
              {
                     value = 0;
                     dict[type] = value;
              }

              dict[type] = ++value;
       }

       watch.Stop();

       if (iterations <= 10)
              return;

       Console.WriteLine("Dictionary  : Iterations: {0:N0}, Elapsed: {1}, Value: {2:N0}",
              iterations, watch.Elapsed, value);
}

public void TimeDictionary2<T>(int iterations)
{
       var dict = new Dictionary<Type, object>();
       object value = 0;

       var watch = Stopwatch.StartNew();
       var type = typeof(T);

       for (int i = 0; i < iterations; i++)
       {
              if (!dict.TryGetValue(type, out value))
              {
                     value = 0;
                     dict[type] = value;
              }

              value = (int)value + 1;
              dict[type] = value;
       }

       watch.Stop();

       if (iterations <= 10)
              return;

       Console.WriteLine("Dictionary2: Iterations: {0:N0}, Elapsed: {1}, Value: {2:N0}",
              iterations, watch.Elapsed, value);
}

Lastly, throw it all together inside of Main(), then fire it up and test it.

using System;
using System.Threading;
using ININ.Messaging;

void Main()
{
       int iterations = 10;
       TimeDictionary<int>(iterations);
       TimeDictionary2<int>(iterations);
       TimeClass<int>(iterations);

       iterations = 10000000;
       TimeDictionary<int>(iterations);
       TimeDictionary2<int>(iterations);
       TimeClass<int>(iterations);
}

The results really are pretty impressive with regards to how much faster this approach is.

DictionaryTrickResults

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>