The astute among you realized right away that PolyDictionary
does not really avoid a cast, it just hides it. The TryGetValue()
has a cast in it, highlighted below,
publicbool TryGetValue<K, V>(Key<K, V> key, out V value) {
object objValue;
if (_table.TryGetValue(key, out objValue)) {
value = (V)objValue;
returntrue;
}
value = default(V);
returnfalse;
}
So, can we get rid of the this cast? Yes, but the results are not very
pleasant. One approach is to create one dictionary for each unique value type
and then find that dictionary by that type and index into it using the key,
instead of storing all the values in the same dictionary. This sounds similar to the
original problem! All we need is a PolyDictionary that maps
T to Dictionary<Key<T>, T>. We could code this but we
couldn't run it because we would be defining PolyDictionary in
terms of itself, consuming all of memory in the process. We need something like
PolyDictionary but isn't a PolyDictionary.
OK, things will now get ugly. Have your barf bags on the stand-by! And, for
the love of God, don't ever put this in a production application!
Now that is off my chest, here is one technique to avoid the cast. You can
create a nested class SubDictionary that has a static instance
variable which maps PolyDictionaries to Dictionary<Key<T>, T>.
We can then parameterize SubDictionary by T which will
create a unique dictionary for each T (I warned you it was ugly).
This is because the CLR treats every instantiation of SubDictionary<T> as a
unique type with unique static variables. Essentially we are tricking the CLR
into producing a dictionary of T to Dictionary<PolyDictionary,Dictionary<Key<T>,T>>.
Since the variable is static we need to find the version that is for the
instance we are using, hence the key of PolyDictionary.
Here is the example,
/* Never, Never use this code! */
class PolyDictionary {
class SubDictionaries<T> {
internalstatic Dictionary<PolyDictionary, Dictionary<Key<T>, T>> Dictionaries =
new Dictionary<PolyDictionary,Dictionary<Key<T>,T>>();
}
public PolyDictionary() { }
publicvoid Add<T>(Key<T> key, T value) {
Dictionary<Key<T>, T> subDictionary = GetDictionary(key);
subDictionary.Add(key, value);
}
public T Get<T>(Key<T> key) {
Dictionary<Key<T>, T> subDictionary = FindDictionary(key);
if (subDictionary != null)
return subDictionary[key];
thrownew KeyNotFoundException();
}
publicbool TryGetValue<T>(Key<T> key, out T value) {
Dictionary<Key<T>, T> subDictionary = FindDictionary(key);
if (subDictionary != null)
return subDictionary.TryGetValue(key, out value);
else {
value = default(T);
returnfalse;
}
}
Dictionary<Key<T>, T> FindDictionary<T>(Key<T> key) {
Dictionary<Key<T>, T> subDictionary;
if (!SubDictionaries<T>.Dictionaries.TryGetValue(this, out subDictionary))
returnnull;
return subDictionary;
}
Dictionary<Key<T>, T> GetDictionary<T>(Key<T> key) {
Dictionary<Key<T>, T> subDictionary;
if (!SubDictionaries<T>.Dictionaries.TryGetValue(this, out subDictionary)) {
subDictionary = new Dictionary<Key<T>, T>();
SubDictionaries<T>.Dictionaries.Add(this, subDictionary);
}
return subDictionary;
}
}
This code has so many problems I don't know where to start. For one, it
never frees memory, the dictionaries are in memory and will never be
collected. I only include it to show that it can be done. As you can see,
sometimes it is better to have a cast. There might be better techniques that
eliminate some of the problems but my feeling is, why bother. The cast is not that
bad.
PolyDictionary III: Cast away
The astute among you realized right away that
PolyDictionarydoes not really avoid a cast, it just hides it. TheTryGetValue()has a cast in it, highlighted below,public bool TryGetValue<K, V>(Key<K, V> key, out V value) { object objValue; if (_table.TryGetValue(key, out objValue)) { value = (V)objValue; return true; } value = default(V); return false; }So, can we get rid of the this cast? Yes, but the results are not very pleasant. One approach is to create one dictionary for each unique value type and then find that dictionary by that type and index into it using the key, instead of storing all the values in the same dictionary. This sounds similar to the original problem! All we need is a
PolyDictionarythat mapsTtoDictionary<Key<T>, T>. We could code this but we couldn't run it because we would be definingPolyDictionaryin terms of itself, consuming all of memory in the process. We need something likePolyDictionarybut isn't aPolyDictionary.OK, things will now get ugly. Have your barf bags on the stand-by! And, for the love of God, don't ever put this in a production application!
Now that is off my chest, here is one technique to avoid the cast. You can create a nested class
SubDictionarythat has a static instance variable which mapsPolyDictionariestoDictionary<Key<T>, T>. We can then parameterizeSubDictionarybyTwhich will create a unique dictionary for eachT(I warned you it was ugly). This is because the CLR treats every instantiation ofSubDictionary<T>as a unique type with unique static variables. Essentially we are tricking the CLR into producing a dictionary ofTtoDictionary<PolyDictionary,Dictionary<Key<T>,T>>. Since the variable is static we need to find the version that is for the instance we are using, hence the key ofPolyDictionary.Here is the example,
/* Never, Never use this code! */ class PolyDictionary { class SubDictionaries<T> { internal static Dictionary<PolyDictionary, Dictionary<Key<T>, T>> Dictionaries = new Dictionary<PolyDictionary,Dictionary<Key<T>,T>>(); } public PolyDictionary() { } public void Add<T>(Key<T> key, T value) { Dictionary<Key<T>, T> subDictionary = GetDictionary(key); subDictionary.Add(key, value); } public T Get<T>(Key<T> key) { Dictionary<Key<T>, T> subDictionary = FindDictionary(key); if (subDictionary != null) return subDictionary[key]; throw new KeyNotFoundException(); } public bool TryGetValue<T>(Key<T> key, out T value) { Dictionary<Key<T>, T> subDictionary = FindDictionary(key); if (subDictionary != null) return subDictionary.TryGetValue(key, out value); else { value = default(T); return false; } } Dictionary<Key<T>, T> FindDictionary<T>(Key<T> key) { Dictionary<Key<T>, T> subDictionary; if (!SubDictionaries<T>.Dictionaries.TryGetValue(this, out subDictionary)) return null; return subDictionary; } Dictionary<Key<T>, T> GetDictionary<T>(Key<T> key) { Dictionary<Key<T>, T> subDictionary; if (!SubDictionaries<T>.Dictionaries.TryGetValue(this, out subDictionary)) { subDictionary = new Dictionary<Key<T>, T>(); SubDictionaries<T>.Dictionaries.Add(this, subDictionary); } return subDictionary; } }This code has so many problems I don't know where to start. For one, it never frees memory, the dictionaries are in memory and will never be collected. I only include it to show that it can be done. As you can see, sometimes it is better to have a cast. There might be better techniques that eliminate some of the problems but my feeling is, why bother. The cast is not that bad.
7:02 PM | Add comment | #Programming