2010-07-22 47 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 
相关问题