2008-10-04 72 views
4

我有類似下面的類:C#泛型類「專業」構造

public class DropDownControl<T, Key, Value> : BaseControl 
    where Key: IComparable 
{ 
    private IEnumerable<T> mEnumerator; 
    private Func<T, Key> mGetKey; 
    private Func<T, Value> mGetValue; 
    private Func<Key, bool> mIsKeyInCollection; 

    public DropDownControl(string name, IEnumerable<T> enumerator, Func<T, Key> getKey, Func<T, Value> getValue, Func<Key, bool> isKeyInCollection) 
     : base(name) 
    { 
     mEnumerator = enumerator; 
     mGetKey = getKey; 
     mGetValue = getValue; 

     mIsKeyInCollection = isKeyInCollection; 
    } 

而且我想添加一個方便的功能字典(因爲它們有效地支持自己的所有操作)。

但問題是,這樣的構造函數只會指定鍵和值但不直接T,而T是剛剛KeyValuePair。有沒有辦法告訴了此構造T中的編譯器是KeyValuePair,如:

public DropDownControl<KeyValuePair<Key, Value>>(string name, IDictionary<Key, Value> dict) { ... } 

目前我使用靜態的創建功能的解決方法,但我想直接的構造更好。

public static DropDownControl<KeyValuePair<DKey, DValue>, DKey, DValue> Create<DKey, DValue>(string name, IDictionary<DKey, DValue> dictionary) 
      where DKey: IComparable 
     { 
      return new DropDownControl<KeyValuePair<DKey, DValue>, DKey, DValue>(name, dictionary, kvp => kvp.Key, kvp => kvp.Value, key => dictionary.ContainsKey(key)); 
     } 

回答

12

不,基本上。在非泛型類的靜態方法(如DropDownControl [無< >)是最好的辦法,因爲你應該能夠當你調用Create()使用類型推斷 - 即

var control = DropDownControl.Create(name, dictionary); 

C# 3.0通過「var」(這裏非常受歡迎)和大大改進的泛型類型推斷規則在這裏幫助。在一些(更普遍的)情況下,另一個類似的選項是一種擴展方法,但擴展方法來創建從字典中一個非常特殊的控制並不感到很自然 - 我最好使用非擴展方法。

喜歡的東西:

public static class DropDownControl 
{ 
    public static DropDownControl<KeyValuePair<TKey,TValue>, TKey, TValue> 
      Create<TKey,TValue>(IDictionary<TKey, TValue> value, string name) 
    where TKey : IComparable 
    { 
     return new DropDownControl<KeyValuePair<TKey, TValue>, TKey, TValue> 
      (name, value, pair => pair.Key, pair => pair.Value, 
      key => value.ContainsKey(key) 
     ); 
    } 
} 

另一種選擇是繼承,但我不喜歡它了...

public class DropDownControl<TKey, TValue> : 
    DropDownControl<KeyValuePair<TKey, TValue>, TKey, TValue> 
    where TKey : IComparable 
{ 
    public DropDownControl(IDictionary<TKey, TValue> lookup, string name) 
     : base(name, lookup, pair => pair.Key, pair => pair.Value, 
      key => lookup.ContainsKey(key)) { } 
} 

這增加了複雜性,並降低你的靈活性......我不會」做T這...

總體而言,這聽起來像你想只IDictionary的<合作,> - 我不知道,如果你不能簡化你的控制,只是利用這一點,並迫使非字典呼叫者包裹自己一個IDictionary <,>門面?

+0

那麼我正在尋找一種方法來做類似於C++部分模板的特化。但似乎C#目前無法做到這一點(甚至沒有技巧)。 – Fionn 2008-10-06 08:37:19

0

如果T將始終爲KeyValuePair<TKey,TValue>根本不需要它是一個泛型類型參數。只需使用您使用的每個地方的實際類型T。否則,如果類型有時必須是別的東西,我建議你應該有一個DropDownControl<TKey, TValue> : BaseControl的基類型,它具有相同類型的受保護字段Helper,幾乎所有方法的虛擬實現都可以簡單地調用它們對口Helper;在那裏定義派生類HeldAs<TPair>,它覆蓋了所有使用「真實」實現的方法。

DropDownControl<TKey,TValue>的構造函數將構造一個新的DropDownControl<TKey,TValue>.HeldAs<KeyValuePair<TKey,TValue>>實例並存儲在Helper中的引用。然後外部代碼可以持有類型DropDownControl<TKey,TValue>的引用並使用它們而不必知道或關心如何保存鍵和值。這就需要創造一些存儲的東西的不同方式,使用不同的方法來提取鍵和值可以調用的DropDownControl<TKey,TValue>.HeldAs<actualStorageType>構造,通過它可以轉換actualStorageType密鑰或值相應的功能代碼。

如果有任何的DropDownControl<TKey,TValue>方法將有望通過this,那麼DropDownControl<TKey,TValue>.HeldAs<TStorage>構造函數應該設置Helper本身,但基本類型的構造方法,構建派生類型實例之後,應設置派生的實例的Helper引用本身(基類包裝器)。然後通過this的方法應該通過Helper。這將確保當派生類實例純粹是爲了被包裝而構建時,外部世界將永遠不會接收到對該派生實例的引用,而是始終會看到包裝器。