簡體   English   中英

使用Where指定不同的泛型

[英]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)映射32[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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM