【问题标题】:How to create a type that implement IDictionary<'K, 'V> and IEnumerable<'V>如何创建实现 IDictionary<'K, 'V> 和 IEnumerable<'V> 的类型
【发布时间】:2010-07-22 16:52:17
【问题描述】:

我想创建一个实现 IDictionary 和 IEnumerable 的只读键控集合。采取明显的方法,我得到以下错误:

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

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

编辑 - 既然这似乎是 F# 不可逾越的限制,那么实现这一点的惯用方式是什么?想到的一个想法是提供返回所需数据视图的成员,例如成员 x.List : IList 和成员 x.Dict : IDictionary。对象表达式可用于提供实现。还有其他想法吗?

【问题讨论】:

    标签: f#


    【解决方案1】:

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

    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
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          猜你喜欢
          • 2011-03-06
          • 2013-06-24
          • 1970-01-01
          • 2011-07-31
          • 2010-09-26
          • 2010-09-21
          • 1970-01-01
          • 1970-01-01
          • 2018-10-07
          相关资源
          最近更新 更多