2010-07-22 54 views
7

我想要創建一個只讀的鍵集合,它實現了IDictionary <'K,'V>和IEnumerable <'V>。以明顯的方法,我得到以下錯誤:如何創建一個類型,實現IDictionary <'K, 'V>和IEnumerable <'V>

This type implements or inherits the same interface at different generic instantiations 'IEnumerable<'V>' and 'IEnumerable<KeyValuePair<'K,'V>>'. This is not permitted in this version of F#.

是否有實現這一目標的一個不同的方式?

編輯 - 由於這似乎是F#不可逾越的限制,實現這一目標的習慣方式是什麼?想到的一個想法是提供返回所需數據視圖的成員,例如成員x.List:IList <'V>和成員x.Dict:IDictionary <'K,'V>。對象表達式可以用來提供實現。任何其他想法?

回答

3

恐怕不是。 CLR允許實現多個接口(甚至是相同的基本類型),但不能使用F#語言。如果你用C#編寫這個類,我相信你不會有任何問題,但是F#會在當前版本中給你帶來問題。

2

正如Noldorin所說,這是不可能的。一種慣用方法是在與您的類型名稱相同的模塊上提供toSeqtoDict函數(如List.toSeqArray.toSeq等)。

7

一個相對簡單的方法是將兩個接口的實現公開爲您正在編寫的類型的成員。這可以通過使用對象表達式或者只是通過編寫構造某種類型的代碼並將其作爲結果返回來完成。第二種方法是這樣的:

type MyCollection<'K, 'V when 'K : equality>(keys:list<'K>, values:list<'V>) = //' 
    member x.Dictionary = 
    Seq.zip keys values |> dict 
    member x.Enumerable = 
    values |> List.toSeq 

第一種方法(如果你想實現的接口的方法,直接將看起來大致是這樣的:

type MyCollection<'K, 'V when 'K : equality>(keys:list<'K>, values:list<'V>) = //' 
    member x.Dictionary = 
    { new IDictionary<'K, 'V> with 
     member d.Add(k, v) = ... }    
    member x.Enumerable = 
    // Similarly for IEnumerable 
    values |> List.toSeq 

暴露的實現作爲功能模塊中正如kvb所提到的,這也是一個很好的選擇 - 我認爲許多標準的F#庫類型實際上都執行了這兩個選項(以便用戶可以選擇他/她喜歡的樣式)。可以這樣添加:

module MyCollection = 
    let toDict (a:MyCollection<_, _>) = a.Dictionary 
相關問題