I'm writing a bijective dictionary class, but I want to ensure the two generic types are not the same type for two reasons.
Firstly, I would like it to implement the IDictionary
interface in both directions, but
public class BijectiveDictionary<TKey, TValue>
: IDictionary<TKey, TValue>, IDictionary<TValue, TKey>
gives me " 'BijectiveDictionary<TKey,TValue>' cannot implement both 'IDictionary<TKey,TValue>' and 'IDictionary<TValue,TKey>' because they may unify for some type parameter substitutions " (which is understandable, but undesirable.)
Secondly, I would like to write an optimized solution if both types are the same.
public class BijectiveDictionary<TKey, TValue>
: IDictionary<TKey, TValue> where TValue : TKey
{
// Optimized solution
}
public class BijectiveDictionary<TKey, TValue>
: IDictionary<TKey, TValue>, IDictionary<TValue, TKey> where TValue : !TKey
{
// Standard solution
}
Is this possible?
If not, I can consider not implementing IDictionary
, but I couldn't guarantee TValue this[TKey key]
and TKey this[TValue key]
would be different, which would be unfortunate.
It looks like the problem here is that when the two types are the same, the special cases arise.
My original intent was to create a dictionary which maps exactly one key to exactly one value, and visa versa, such that for every KeyValuePair<TKey, TValue>(X, Y)
, a KeyValuePair<TValue, TKey>(Y, X)
exists as well.
When TKey
= TValue
, then this can be simplified down to a single dictionary:
public T this[T key]
{
get { return this[key]; }
set
{
base.Add(key, value);
base.Add(value, key);
}
}
In this case, you cannot Add(2,3); Add(3,4)
because Add(2,3)
maps 3
to 2
as well, and [3]
would return 2
.
However, Jaroslav Jandek's solution proposed using a second dictionary to do this for cases when TKey
!= TValue
. And although this works wonderfully for those cases, (and what I decided to implement, in the end) it doesn't quite follow my original intent when TKey
= TValue
, by allowing Add(2,3); Add(3,4)
to map a single key 3
to two values (2
in one direction, and 4
in the other,) though I believe strictly speaking is still a valid bijective function.
A Generic class can have muliple type parameters.
Generics means parameterized types. The idea is to allow type (Integer, String, … etc., and user-defined types) to be a parameter to methods, classes, and interfaces. Using Generics, it is possible to create classes that work with different data types.
How about this (different approach):
public class BijectiveDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
public BijectiveDictionary<TValue, TKey> Reversed { get; protected set; }
public BijectiveDictionary()
{
this.Reversed = new BijectiveDictionary<TValue,TKey>(true);
this.Reversed.Reversed = this;
}
protected BijectiveDictionary(bool reversedWillBeSetFromTheCallingBiji) { }
protected void AddRaw(TKey key, TValue value)
{
base.Add(key, value);
}
// Just for demonstration - you should implement the IDictionary interface instead.
public new void Add(TKey key, TValue value)
{
base.Add(key, value);
this.Reversed.AddRaw(value, key);
}
public static explicit operator BijectiveDictionary<TValue, TKey>(BijectiveDictionary<TKey, TValue> biji)
{
return biji.Reversed;
}
}
and in code:
BijectiveDictionary<int, bool> a = new BijectiveDictionary<int, bool>();
a.Add(5, true);
a.Add(6, false);
Console.WriteLine(a[5]);// => True
Console.WriteLine(((BijectiveDictionary < bool, int>)a)[true]);// => 5
//or
Console.WriteLine(a.Reversed[true]);// => 5
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With