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.

Était-ce utile?

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

Qu'est-ce que ce regard de code C # comme dans F #?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top