2010-03-19 9 views
33

J'ai un morceau de code où je dois savoir si un type donné implémente IEnumerable<T> (je ne me soucie pas du T)F # équivalent du C# typeof (IEnumerable <>)

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<>> 
    ) 

cependant que ne compilera pas (la compilation n'aime pas le <>). J'ai alors essayé

let interfaces = t.GetInterfaces() 
let enumerbale = 
    interfaces.Any(fun t -> 
     t.GetGenericTypeDefinition() = typeof<IEnumerable<'a>> 
    ) 

mais obtiens un avertissement que 'a est une contrainte à obj. Je ne veux pas comprendre si IEnumerable<obj> est implémenté mais IEnumerabl<>.

Tout le monde connaît la solution et btw n'hésitez pas à commenter le code ci-dessus.

+0

http://stackoverflow.com/questions/1652050/generic-type-definition- syntaxe-sur-f –

Répondre

49

Cela devrait fonctionner:

typedefof<System.IEnumerable<_>> 

EDIT

Comme Tomas note, il n'y a rien de spécial ici le caractère générique _; F # déduit que le type obj est le type applicable le plus général dans ce contexte, donc c'est la même chose que d'utiliser typedefof<System.IEnumerable<obj>>. Dans certains cas, la façon dont cela fonctionne peut être un peu gênant. Par exemple, si vous définissez une interface type I<'a when 'a :> I<'a>> = interface end, vous ne pouvez pas utiliser typedefof<I<_>>, car 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écursives (par exemple, type I<'a when 'a : struct and 'a :> System.ICloneable> = interface end), contrairement à l'approche de C#, qui fonctionne parfaitement dans les cas analogues

En ce qui concerne votre code, je pense que vous voudrez apporter d'autres modifications, . aussi, comme veiller à ce 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>)) 
+0

Votre solution m'a sauvé d'un autre problème :) avec errormessage pas si utile "non pris en charge en raison de l'état actuel de l'objet" qui est une façon de dire ne peut pas appeler getgenerictypedefinition ón un type non générique –

17

pour autant que je sache, F # n'a pas d'équivalent à C# 's typeof(IEnumerable<>) Ceci est car, il s'agit d'une syntaxe spéciale prise en charge explicitement par C# En F #, typeof est une fonction normale et l'argument de type doit être un type entièrement spécifié. définition de type eneric 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 en déduit que le paramètre type n'est pas restreint, il utilise le type par défaut obj.

EDIT Je ne connaissais pas typedefof<IEnumerable<_>>, c'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.

+0

la clarification de la _ –

Questions connexes