Próbuję wywołać metodę .NET akceptującą generyczne IEnumerable<T>
z F # przy użyciu seq<U>
tak, że U jest podklasą T. To nie działa tak, jak się spodziewałem by:F # i kowariancja interfejsu: co zrobić? (szczególnie seq <> aka IEnumerable <>)
z następującym prostym drukarki:
let printEm (os: seq<obj>) =
for o in os do
o.ToString() |> printfn "%s"
są to wyniki uzyskać:
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 '[email protected][System.Int32]'
// to type 'System.Collections.Generic.IEnumerable`1[System.Object]'.
Idealnie chciałbym pierwszy składni do pracy - lub coś w pobliżu to jak po ssible, z sprawdzaniem typu kompilacji. Nie rozumiem, gdzie kompilator znajduje funkcję seq<string> -> unit
w tej linii, ale najwyraźniej kowariancja dla IEnumerable nie działa i że w jakiś sposób powoduje to komunikat o błędzie. Użycie jawnego rzutowania daje uzasadniony komunikat o błędzie - ale to też nie działa. Używanie rzutowania działa - ale tylko dla łańcuchów, ints kończy się niepowodzeniem z wyjątkiem (nieprzyjemnym).
Próbuję współpracować z innym kodem .NET; dlatego potrzebuję konkretnych typów IEnumerable.
Jaki jest najczystszy i najskuteczniejszy sposób przesyłania współosiowych lub sprzecznych interfejsów, takich jak IEnumerable w F #?
Jak mówi Desco, najczystszym rozwiązaniem jest zmienić (lub usunąć) deklarację typu na 'os' (jeśli to możliwe). W przypadku niepowiązanej notki, 'o.ToString |> printfn"% s "' może być napisane bardziej zwięźle jako 'o |> printfn"% O "'. – kvb
@kvb Myślę, że @Eamon nie ma problemu z funkcją 'printfn'. –