[英]Using Where to specify different generics
我正在寫一個雙向字典類 ,但我想確保兩個泛型類型不是同一類型,原因有兩個。
首先,我希望它在兩個方向上實現IDictionary
接口,但是
public class BijectiveDictionary<TKey, TValue>
: IDictionary<TKey, TValue>, IDictionary<TValue, TKey>
給我“'BijectiveDictionary <TKey,TValue>'不能同時實現'IDictionary <TKey,TValue>'和'IDictionary <TValue,TKey>'因為它們可能統一某些類型參數替換”(這是可以理解的,但不可取的。)
其次,如果兩種類型相同,我想編寫一個優化的解決方案。
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
}
這可能嗎?
如果沒有,我可以考慮不實現IDictionary
,但我不能保證TValue this[TKey key]
和TKey this[TValue key]
會有所不同,這是不幸的。
看起來這里的問題是當兩種類型相同時,會出現特殊情況。
我的初衷是創建一個字典,將一個鍵恰好映射到一個值,反之亦然,這樣每個KeyValuePair<TKey, TValue>(X, Y)
, KeyValuePair<TValue, TKey>(Y, X)
也存在。
當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); Add(3,4)
因為Add(2,3)
映射3
到2
, [3]
將返回2
。
然而, Jaroslav Jandek的解決方案提出使用第二個字典來處理TKey
!= TValue
。 雖然這對於那些情況非常有效,(以及我最終決定實施的情況)但是當TKey
= TValue
,通過允許Add(2,3); Add(3,4)
它並不完全符合我原來的意圖Add(2,3); Add(3,4)
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
在某種程度上,這可以做到! 我使用差異化方法,而不是限制類型的限定符。
它沒有統一,事實上它可能比它更好,因為你可以分開挑逗單獨的接口。
在這里查看我的帖子,在另一個上下文中有一個完整的例子。 https://stackoverflow.com/a/12361409/471129
基本上,你要做的是為IIndexer
添加另一個類型參數,以便它成為IIndexer <TKey, TValue, TDifferentiator>
。
然后當你使用它兩次時,你將“First”傳遞給第一次使用,將“Second”傳遞給第二次使用
因此,類Test成為: class Test<TKey, TValue> : IIndexer<TKey, TValue, First>, IIndexer<TValue, TKey, Second>
因此,你可以做new Test<int,int>()
第一和第二是微不足道的:
interface First { }
interface Second { }
簡而言之,沒有。 重新優化它,一個選項可能是基於靜態初始化程序的策略,為相同類型的情況選擇適當的具體實現,否則; 即
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?
也許你可以用另一種不模糊的方式重構你的代碼?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.