如何创建一个实现IDictionary的类型<'K,'V>和IEnumerable<'V>

时间:2010-07-22 16:52:18

标签: f#

我想创建一个只读的键控集合,它实现了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&lt;'V&gt;和成员x.Dict:IDictionary&lt;'K,'V&gt;。对象表达式可用于提供实现。还有其他想法吗?

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:3)

答案 2 :(得分:2)

正如Noldorin所说,这是不可能的。一种惯用方法是在模块上提供toSeqtoDict函数,其名称与您的类型相同(例如List.toSeqArray.toSeq等。)