Я пишу bijective класс словаря, но я хочу удостовериться, что два универсальных типа не являются тем же типом по двум причинам.
Во-первых, я хотел бы, чтобы это реализовало IDictionary
интерфейс в обоих направлениях, но
public class BijectiveDictionary
: IDictionary, IDictionary
дает мне "'BijectiveDictionary
Во-вторых, я хотел бы записать оптимизированное решение, если оба типа являются тем же.
public class BijectiveDictionary
: IDictionary where TValue : TKey
{
// Optimized solution
}
public class BijectiveDictionary
: IDictionary, IDictionary where TValue : !TKey
{
// Standard solution
}
Действительно ли это возможно?
В противном случае я могу рассмотреть не реализацию IDictionary
, но я не мог гарантировать TValue this[TKey key]
и TKey this[TValue key]
отличалось бы, который будет неудачен.
Похоже, что проблема вот состоит в том, что, когда два типа являются тем же, особые случаи возникают.
Мое исходное намерение состояло в том, чтобы создать словарь, который отображает точно один ключ точно к одному значению и стих визы, такой это для каждого KeyValuePair
, a KeyValuePair
существует также.
Когда TKey
= TValue
, затем это может быть упрощено вниз до единственного словаря:
public T this[T key]
{
get { return this[key]; }
set
{
base.Add(key, value);
base.Add(value, key);
}
}
В этом случае Вы не можете Add(2,3); Add(3,4)
потому что Add(2,3)
карты 3
кому: 2
также, и [3]
возвратился бы 2
.
Однако решение Jaroslav Jandek предложило использовать второй словарь, чтобы сделать это для случаев когда TKey
!= TValue
. И хотя это работает замечательно на те случаи, (и что я решил реализовать в конце), он не вполне следует за моим исходным намерением когда TKey
= TValue
, путем разрешения Add(2,3); Add(3,4)
отобразить единственный ключ 3
к двум значениям (2
в одном направлении, и 4
в другом), хотя я верю строго говоря, все еще допустимая биективная функция.
Как насчет этого (другого подхода):
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;
}
}
и в коде:
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
Короче говоря, нет. Что касается оптимизации, то одним из вариантов может быть стратегия, основанная на статическом инициализаторе, который выбирает подходящую конкретную реализацию для однотипного случая, но иначе; т.е.
public class BijectiveDictionary<TKey, TValue>
: IDictionary<TKey, TValue>
{
static readonly ISomeStrategy strategy;
static BijectiveDictionary() {
if(typeof(TKey) == typeof(TValue)) {
strategy = ...
} else {
strategy = ...
}
}
}
но вы почти наверняка обнаружите, что используете MakeGenericType
и рефлексию для создания экземпляра (но после создания он должен быть в порядке - и вы делаете это только один раз).
Даже если бы вы могли, каков был бы вывод этого кода?
var dict = new BijectiveDictionary<int, int>();
dict.Add(2,3);
dict.Add(3,4);
Console.WriteLine(dict[3]); // Do I get 2 or 4?
Может быть, вы можете перестроить свой код другим способом, который не будет двусмысленным?