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

Dan*_*iel 7 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 <'V>和成员x.Dict:IDictionary <'K,'V>.对象表达式可用于提供实现.还有其他想法吗?

Tom*_*cek 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
Run Code Online (Sandbox Code Playgroud)

第一种方法(如果你想直接实现接口的方法看起来大致如下:

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
Run Code Online (Sandbox Code Playgroud)

将实现作为函数暴露在kvb提到的模块中也是一个很好的选择 - 我认为许多标准的F#库类型实际上都做了两个选项(这样用户可以选择他/她喜欢的样式).这可以像这样添加:

module MyCollection = 
  let toDict (a:MyCollection<_, _>) = a.Dictionary
Run Code Online (Sandbox Code Playgroud)


Nol*_*rin 3

恐怕不是。当然,CLR 允许实现多个接口(即使是相同的基类型),但 F# 语言不允许。我相信如果你用 C# 编写类,你不会有任何问题,但 F# 在当前版本中会给你带来问题。