2010-07-22 9 views
7

Quiero crear una colección de sólo lectura con llave que implementa IDictionary < 'K', V> y IEnumerable < 'V>. Tomando el enfoque obvio me sale el siguiente error:Cómo crear un tipo que implementan IDictionary <'K, 'V> y 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#.

¿Hay una manera diferente de lograr esto?

EDIT - Dado que esto parece ser una limitación infranqueable de F #, ¿cuál sería una forma idiomática de lograr esto? Un pensamiento que viene a la mente es proporcionar a los miembros que devuelvan la vista deseada de los datos, por ejemplo, miembro x.List: IList < 'V> y miembro x.Dict: IDictionary <' K, 'V>. Las expresiones de objeto se podrían usar para proporcionar las implementaciones. ¿Alguna otra idea?

Respuesta

3

Me temo que no. El CLR permite la implementación de múltiples interfaces por supuesto (incluso del mismo tipo base), pero no el lenguaje F #. Creo que no tendrás ningún problema si escribes la clase en C#, pero F # te dará problemas en la versión actual.

2

Como dice Noldorin, esto no es posible. Un enfoque idiomático es proporcionar funciones toSeq y toDict en un módulo con el mismo nombre que su tipo (como List.toSeq, Array.toSeq, etc.).

7

Un enfoque relativamente fácil es exponer la implementación de las dos interfaces como miembros del tipo que está escribiendo. Esto se puede hacer bastante bien utilizando expresiones de objeto o simplemente escribiendo un fragmento de código que construye algún tipo y lo devuelve como resultado. El segundo enfoque se vería así:

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 

El primer enfoque (si se desea implementar los métodos de las interfaces directamente se vería más o menos así:

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 

La exposición de las implementaciones como las funciones en un módulo como lo menciona kvb también es una gran opción. Creo que muchos de los tipos de biblioteca estándar F # hacen ambas opciones (para que el usuario pueda elegir el estilo que prefiera). Esto se puede agregar así:

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