Как создать тип, который реализует IDictionary <'K,' V> и IEnumerable <'V> - PullRequest
7 голосов
/ 22 июля 2010

Я хочу создать коллекцию ключей только для чтения, которая реализует 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#.

Есть ли другой способ достижения этого?

РЕДАКТИРОВАТЬ - С этого моментакажется непреодолимым ограничением F #, что было бы идиоматическим способом достижения этого?Одна мысль, которая приходит на ум, - это предоставление членов, которые возвращают желаемый вид данных, например, член x.List: IList <'V> и член x.Dict: IDictionary <' K, 'V>.Выражения объекта могут быть использованы для предоставления реализации.Есть другие идеи?

Ответы [ 3 ]

7 голосов
/ 22 июля 2010

Один из относительно простых подходов - представить реализацию двух интерфейсов как членов типа, который вы пишете. Это можно сделать довольно просто, используя выражения объекта или просто написав фрагмент кода, который создает некоторый тип и возвращает его в результате. Второй подход будет выглядеть так:

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 голосов
/ 22 июля 2010

Боюсь, что нет. Разумеется, CLR позволяет реализовать несколько интерфейсов (даже одного базового типа), но не язык F #. Я полагаю, что у вас не будет проблем, если вы напишите класс на C #, но F # создаст вам проблемы в текущей версии.

2 голосов
/ 22 июля 2010

Как говорит Нолдорин, это невозможно. Один идиоматический подход заключается в предоставлении функций toSeq и toDict для модуля с тем же именем, что и ваш тип (например, List.toSeq, Array.toSeq и т. Д.).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...