代码之家  ›  专栏  ›  技术社区  ›  Daniel

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

f#
  •  7
  • Daniel  · 技术社区  · 16 年前

    我想创建一个实现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#.

    有没有不同的方法来实现这一点?

    编辑

    3 回复  |  直到 16 年前
        1
  •  3
  •   Noldorin    16 年前

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

        2
  •  7
  •   Tomas Petricek    16 年前

    一种相对简单的方法是将两个接口的实现公开为您正在编写的类型的成员。这可以通过使用 或者仅仅通过编写一段代码来构造某种类型并将其作为结果返回。第二种方法如下所示:

    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
    
        3
  •  2
  •   kvb    16 年前

    正如诺尔多林所说,这是不可能的。一种惯用的方法是提供 toSeq toDict 与类型同名的模块上的函数(如 List.toSeq , Array.toSeq