Почему ключи IDictionary ‹_,› несовместимы с производными типами?

type TypeA () = class end
type TypeB () = inherit TypeA ()

// "The type 'TypeA' does not match the type 'TypeB'":
let iDict : IDictionary<TypeA, bool> = [ TypeB (), true; TypeB (), false ] |> dict

let d = Dictionary<TypeA, bool> ()
// This is OK, though:
d.Add (TypeB (), false)

Почему ключи IDictionary несовместимы с производными типами?


person MiloDC    schedule 17.07.2016    source источник
comment
Привязано к дублированию, но массивы в F # не являются ковариантными - хотя такие перегрузки методов, как add   -  person John Palmer    schedule 17.07.2016
comment
Потому что KeyValuePair<'Key, 'Value> не ковариантен по 'Key?   -  person ildjarn    schedule 17.07.2016
comment
Интересно: прежний блог Эрика Липперта - ключевое слово: ковариация и контравариантность Примечание. Список составлен в обратном хронологическом порядке, поэтому начните с конца и двигайтесь вперед.   -  person Guy Coder    schedule 17.07.2016
comment
Интересно: как устранить несоответствие ограничений типа, C # на F #   -  person Guy Coder    schedule 17.07.2016


Ответы (1)


Давайте посмотрим на различия между двумя подходами:

В первом случае вы создаете список:

[ TypeB (), true; TypeB (), false ]

Это тип (TypeB * bool) list.

dict имеет тип seq<'Key * 'Value> -> IDictionary<'Key,'Value> (requires equality).

Следовательно, применяя функцию dict

dict [ TypeB (), true; TypeB (), false ]

приводит к значению типа IDictionary<TypeB, bool>.

IDictionary<TypeB, bool> не эквивалентно IDictionary<TypeA, bool>, это совершенно разные и несовместимые типы, отсюда и ошибка компилятора.

Если вы хотите таким образом инициализировать свой словарь из коллекции более производных типов, вам придется явно выполнить приведение вверх, например:

let iDict = 
    [ TypeB (), true; TypeB (), false ] 
    |> List.map (fun (a,b) -> (a :> TypeA), b) 
    |> dict

Во втором примере эта проблема не материализовалась, потому что вы изначально создали Dictionary<TypeA, bool>.

Затем вы используете метод Add, чтобы добавить что-нибудь из TypeB в словарь. Поскольку Add - это метод, F # может выполнять автоматическое преобразование аргумента с повышением, так что ваше значение TypeB будет автоматически преобразовано в TypeA.

person TheInnerLight    schedule 17.07.2016