я пытаюсь вызвать .NET-метод, принимающий общий IEnumerable
из F #, используя seq
таким образом, что U является подклассом T. Это не работает так, как я ожидал:
Со следующим простым принтером:
let printEm (os: seq<obj>) =
for o in os do
o.ToString() |> printfn "%s"
Вот результаты, которые я получаю:
Seq.singleton "Hello World" |> printEm // error FS0001;
//Expected seq<string> -> 'a but given seq<string> -> unit
Seq.singleton "Hello World" :> seq<obj> |> printEm // error FS0193;
//seq<string> incompatible with seq<obj>
Seq.singleton "Hello World" :?> seq<obj> |> printEm // works!
Seq.singleton 42 :> seq<obj> |> printEm // error FS0193
Seq.singleton 42 :?> seq<obj> |> printEm // runtime InvalidCastException!
//Unable to cast object of type 'mkSeq@541[System.Int32]'
// to type 'System.Collections.Generic.IEnumerable`1[System.Object]'.
В идеале, я бы хотел, чтобы первый синтаксис работал - или что-то как можно ближе к нему, с проверкой типов во время компиляции. Я не понимаю, где компилятор находит функцию seq
в этой строке, но, по-видимому, ковариация для IEnumerable не работает, и это каким-то образом приводит к тому сообщению об ошибке. Использование явного приведения приводит к разумному сообщению об ошибке, но это тоже не работает. Использование приведений во время выполнения работает, но только для строк, целые числа не работают с исключением (неприятно).
Я пытаюсь взаимодействовать с другим кодом .NET; вот почему мне нужны определенные типы IEnumerable.
What ' s самый чистый и предпочтительно эффективный способ приведения ко- или контравариантных интерфейсов, таких как IEnumerable в F #?