How to create a type that implement IDictionary<'K, 'V> and IEnumerable<'V>
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.).
精彩评论