开发者

How to create a type that implement IDictionary<'K, 'V> and IEnumerable<'V>

开发者 https://www.devze.com 2023-01-08 05:11 出处:网络
I want to create a read-only keyed collection that implements IDictionary<\'K, \'V> and IEnumerable<\'V>. Taking the obvious approach I get the following error:

I want to create a read-only keyed collection that implements IDictionary<'K, 'V> and IEnumerable<'V>. Taking the obvious approach I get the following error:

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#.

Is there a different way of achieving this?

EDIT - Since this seems to be an insurmountable limitation of F#, what would be an idiomatic way of achieving this? One thought that comes to mind is providing members that retu开发者_StackOverflow中文版rn the desired view of the data, e.g., member x.List : IList<'V> and member x.Dict : IDictionary<'K, 'V>. Object expressions could be used to provide the implementations. Any other ideas?


One relatively easy approach is to expose the implementation of the two interfaces as members of the type you are writing. This can be done quite nicely using object expressions or just by writing a piece of code that constructs some type and returns it as the result. The second approach would look like this:

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

The first approach (if you want to implement methods of the interfaces directly would look roughly like this:

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

Exposing the implementations as functions in a module as mentioned by kvb is also a great option - I think that many of the standard F# library types actually do both of the options (so that the user can choose the style he/she prefers). This can be added like this:

module MyCollection = 
  let toDict (a:MyCollection<_, _>) = a.Dictionary


I'm afraid not. The CLR allows implementation of multiple interfaces of course (even of the same base type), but not the F# language. I believe you won't have any problems if you write the class in C#, but F# is going to give you problems in the current version.


As Noldorin says, this is not possible. One idiomatic approach is to provide toSeq and toDict functions on a module with the same name as your type (like List.toSeq, Array.toSeq, etc.).

0

精彩评论

暂无评论...
验证码 换一张
取 消