J'essaie d'appeler une méthode .NET acceptant un IEnumerable<T>
générique de F # en utilisant un seq<U>
tel que U est une sous-classe de T. Cela ne fonctionne pas comme je l'attendais serait:F # et covariance d'interface: que faire? (spécifiquement seq <> aka IEnumerable <>)
Avec l'imprimante simple:
let printEm (os: seq<obj>) =
for o in os do
o.ToString() |> printfn "%s"
Ce sont les résultats que je reçois:
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]'.
Idéalement, je voudrais la première syntaxe pour travailler - ou quelque chose d'aussi proche de comme po ssible, avec la vérification du type de temps de compilation. Je ne comprends pas où le compilateur trouve une fonction seq<string> -> unit
dans cette ligne, mais apparemment covariance pour IEnumerable ne fonctionne pas et que cela entraîne en quelque sorte dans ce message d'erreur. L'utilisation d'une distribution explicite génère un message d'erreur raisonnable, mais cela ne fonctionne pas non plus. Utiliser un cast d'exécution fonctionne - mais seulement pour les chaînes, ints échouent avec une exception (méchant). J'essaie d'interopérer avec un autre code .NET; C'est pourquoi j'ai besoin de types IEnumerable spécifiques. Quel est le moyen le plus propre et de préférence efficace de lancer des interfaces co- ou contravariantes telles que IEnumerable in F #?
Comme le dit Desco, la solution la plus propre est de modifier (ou supprimer) la déclaration de type sur 'os' (si possible). Sur une note non liée, 'o.ToString |> printfn"% s "' peut être écrit de façon plus concise comme 'o |> printfn"% O "'. – kvb
@kvb Je pense que @Eamon n'a pas de problème avec la fonction 'printfn'. –