views:

400

answers:

3

I have a piece of code where I need to figure out if a given type implements IEnumerable (I don't care about the T)

I've tried (t:System.Type in case you wonder)

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

however that wont compile (the compile don't like the <>). I then tried

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

but get's a warning that 'a is constraint to obj. I Don't want to figure out if IEnumerable is implemented but IEnumerabl<>.

Any one know's the solution and btw feel free to comment on the code above as well. It's my first non-trivial F# program

+5  A: 

This should work:

typedefof<System.IEnumerable<_>>

EDIT

As Tomas notes, there's nothing special about the _ wildcard here; F# infers that the type obj is the most general applicable type in this context, so this is the same as using typedefof<System.IEnumerable<obj>>. In some cases the way this works can be a bit of a hindrance, though. For instance, if you define an interface type I<'a when 'a :> I<'a>> = interface end, then you can't use typedefof<I<_>>, because I<obj> doesn't satisfy the generic constraint and F# can't infer another more appropriate type. This can happen even without recursive constraints (e.g. type I<'a when 'a : struct and 'a :> System.ICloneable> = interface end. This is in contrast to C#'s approach, which works perfectly fine in the analogous cases.

As to your code itself, I think you'll want to make some other changes, too, such as ensuring that the interface is generic before calling GetGenericTypeDefinition. Here's how I'd write the test function:

(fun t -> t.IsGenericType && (t.GetGenericTypeDefinition() = typedefof<_ seq>))
kvb
seeing it it's so obvious that I should at least have tried it. Thanks for the help
Rune FS
Your solution saved me from another problem :) with not so helpful errormessage "unsupported due to the current State of the object" which is a Way of saying can't Call getgenerictypedefinition ón a non generic type
Rune FS
+1  A: 

As far as I know, F# doesn't have any equivalent to C#'s typeof(IEnumerable<>). This is because, this is a special syntax supported explicitly by C#. In F#, typeof is a normal function and the type argument needs to be a fully specified type. You can get a generic type definition programatically like this:

let t = typeof<IEnumerable<obj>>
let genericT = t.GetGenericTypeDefinition()

The problem with your solution with IEnumerable<'a> is that the F# compiler still needs to find some concrete type to use (as generic type definition isn't a valid type). If the type inference deduces that the type parameter isn't restricted in any way, it uses default type, which is obj.

EDIT I didn't know about typedefof<IEnumerable<_>>, that is very useful! Anyway, note that the underscore doesn't have any special meaning here - the actual type argument is still IEnumerable<obj>, but the typedefof function calls GetGenericTypeDefinition behind the scene.

Tomas Petricek
THanks for the clarification of the _
Rune FS
+3  A: 

I would be remiss not to point out that this question is one of many whose answers are found in

What does this C# code look like in F#?

Brian