F # équivalent du C # typeof (IEnumerable <>)
-
21-09-2019 - |
Question
J'ai un morceau de code où je dois savoir si un type donné implémente IEnumerable<T>
(je ne se soucient pas du T)
J'ai essayé (t:System.Type
dans le cas où vous vous demandez)
let interfaces = t.GetInterfaces()
let enumerbale =
interfaces.Any(fun t ->
t.GetGenericTypeDefinition() = typeof<IEnumerable<>>
)
mais qui ne compilera pas (la compilation n'aime pas le <>). J'ai ensuite essayé
let interfaces = t.GetInterfaces()
let enumerbale =
interfaces.Any(fun t ->
t.GetGenericTypeDefinition() = typeof<IEnumerable<'a>>
)
mais je reçois est un avertissement que « une contrainte est OBJ. Je ne veux pas savoir si IEnumerable<obj>
est mis en œuvre, mais IEnumerabl<>
.
Tout savoir est la solution et BTW ne hésitez pas à commenter le code ci-dessus ainsi.
La solution
Cela devrait fonctionner:
typedefof<System.IEnumerable<_>>
EDIT
Comme Tomas note, il n'y a rien de spécial sur le caractère générique _
ici; F # infère que le type obj
est le plus grand type applicable dans ce contexte, c'est donc le même que l'utilisation typedefof<System.IEnumerable<obj>>
. Dans certains cas, la façon dont cela fonctionne peut-être un peu d'un obstacle, cependant. Par exemple, si vous définissez une type I<'a when 'a :> I<'a>> = interface end
d'interface, vous ne pouvez pas utiliser typedefof<I<_>>
, parce que I<obj>
ne satisfait pas la contrainte générique et F # ne peut pas déduire un autre type plus approprié. Cela peut se produire même sans contraintes récursifs (par exemple type I<'a when 'a : struct and 'a :> System.ICloneable> = interface end
. Ceci est en contraste avec l'approche de C #, qui fonctionne parfaitement bien dans les cas analogues.
En ce qui concerne votre code lui-même, je pense que vous aurez envie de faire d'autres changements, aussi, que faire en sorte que l'interface est générique avant d'appeler GetGenericTypeDefinition
. Voici comment j'écrire la fonction de test:
(fun t -> t.IsGenericType && (t.GetGenericTypeDefinition() = typedefof<_ seq>))
Autres conseils
Pour autant que je sache, F # n'a pas d'équivalent à typeof(IEnumerable<>)
de C #. En effet, ceci est une syntaxe spéciale explicitement prise en charge par C #. En F #, typeof
est une fonction normale et l'argument de type doit être un type entièrement spécifié. Vous pouvez obtenir une définition de type générique programatically comme ceci:
let t = typeof<IEnumerable<obj>>
let genericT = t.GetGenericTypeDefinition()
Le problème avec votre solution avec IEnumerable<'a>
est que le compilateur F # a encore besoin de trouver un certain type de béton à utiliser (comme définition de type générique est pas un type valide). Si l'inférence de type déduit que le paramètre de type ne se limite pas en aucune façon, il utilise le type par défaut, qui est obj
.
EDIT Je ne savais pas typedefof<IEnumerable<_>>
, qui est très utile! Quoi qu'il en soit, notez que le trait de soulignement n'a pas de signification particulière ici - l'argument de type réel est toujours IEnumerable<obj>
, mais la fonction typedefof
appelle GetGenericTypeDefinition
derrière la scène
Je voudrais de ne pas souligner que cette question est l'une des nombreuses dont les réponses se trouvent dans