Acceptable to use a Type for a Dictionary Key?

.net-3.5, c#, data-structures, dictionary

Solution

Yes `Type` is fine as a key; thread-safety is a concern, though - in many ways `Hashtable` is better at threaded-scenarios. However, there is a better option since you are using generics: cheat:

class SessionVariables {
    static class Cache<T> where T : ISessionVariable, new() {
        public static readonly ISessionVariable Value = new T();
    }
    ISessionVariable Get<T>() where T : ISessionVariable, new() {
        return Cache<T>.Value;
    }
}

Which is now fully thread-safe (without "returned different instances" issues) without any dictionary costs.

Edit on the topic of `Hashtable` for Jon:

`Dictionary<TKey,TValue>` makes no guarantees on concurrency, so you are required to synchronize all access - including the reads, as another thread doing a write can break a reader (you can force this in an example, but like most thread-races, it is hard to reproduce).

By contract, `Hashtable` guarantees that it is safe for any number of readers, plus at most one writer. From MSDN:

Hashtable is thread safe for use by multiple reader threads and a single writing thread. It is thread safe for multi-thread use when only one of the threads perform write (update) operations, which allows for lock-free reads provided that the writers are serialized to the Hashtable.

This means that you can do things like:

var val = (SomeType)hash[key];
if(val == null) {
   // not there; actually compute / create the value
   val = ...
   // and store it for the next access
   lock(syncLock) {
       hash[key] = val; // note: could do double-check here
   }
}
return val;

Notice that the read cycle above does not require any synchronization; only the writes need to be synchronized. Note also that because `Hashtable` uses `object`, it works best when the keys and values are classes (not structs).

Yes, concurrent dictionaries now exist - but the above works just fine.

Problem

I would like to make a class that can store at most one copy of an object. All the objects stored here will share the same base class, and I would like to be able to get an object based on it's type. I've come up with this solution so far, but I feel like I'm doing something wrong with using a Type for the Dictionary key. Base class used in multiple modules ``` interface ISessionVariables { } ``` Example of common singleton class used for accessing ``` public class SessionVariables { private object _sync = new object(); private Dictionary<Type, ISessionVariables> _sessionVariables = new Dictionary<Type, ISessionVariables>; public T Get<T>() where T : ISessionVariable, new() { lock (_sync) { ISessionVariables rtnValue = null; if (_sessionVariables.TryGetValue(typeof(T), out rtnValue)) return (T)rtnValue; rtnValue = new T(); _sessionVariables.Add(typeof(T), rtnValue); return (T)rtnValue; } } } ``` This way I can call it like this from individual modules ``` SessionVariableSingleton.Get<ModuleASessionVars>().PropertyA; SessionVariableSingleton.Get<ModuleCSessionVars>().PropertyC; ``` Is this an acceptable way of storing this kind of data structure? Or is there a better alternative using a List or a dictionary without a Type key?

Original source