Давайте посмотрим на различия между этими двумя подходами:
В первом случае, вы создаете список:
[ 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
.
Связано с дубликатом, но массивы в F # не ковариантны - методы перегрузки, такие как добавление, хотя –
Потому что 'KeyValuePair <'Key,' Value>' не ковариантно на '' Key'? – ildjarn
Интересует: [Erstwhile Блог Эрика Липперта - ключевое слово: ковариация и контравариантность] (https://blogs.msdn.microsoft.com/ericlippert/tag/covariance-and-contravariance/) Примечание: список находится в обратном хронологическом порядке, поэтому начинайте с конца и работайте вперед. –