views:

932

answers:

5

I want to determine if a generic object type ("T") method type parameter is a collection type. I would typically be sending T through as a Generic.List but it could be any collection type as this is used in a helper function.

Would I be best to test if it implements IEnumerable<T>?

If so, what would the code look like?

Update 14:17 GMT+10 Possibly extending on a solution here (however only works for List<T>'s not IEnumerable<T>'s when it should if List derives ?)

T currentObj;    
// works if currentObj is List<T>
currentObj.GetType().GetGenericTypeDefinition() == typeof(List<>)
// does not work if currentObj is List<T>
currentObj.GetType().GetGenericTypeDefinition() == typeof(IEnumerable<>)
A: 

I would test IEnumerable instead, since collection type could only implement IEnumerable , it doesn't have to implement IEnumerable.

It also depends what do you mean collection type? You could have an collection without implementing any of those interfaces.

J.W.
Well any object which can hold a list of objects. I'd truly only be using List<T> but a generic handler would have been nicer.
GONeale
+2  A: 

You can use Type.GetInterface() with the mangled name.

private bool IsTAnEnumerable<T>(T x)
{
    return null != typeof(T).GetInterface("IEnumerable`1");
}
Jonathan
Any reason for the null on the left side?
Samuel
As opposed to on the right? Old habits of a C programmer where a flubbed "if (i=0)" is an assignment within the conditional, not a compile error.
Jonathan
+3  A: 

In order to get the actual type of T at runtime, you can use the typeof(T) expression. From there the normal type comparison operators will do the trick

bool isEnumerable = typeof(IEnumerable<int>).IsAssignableFrom(typeof(T));

Full Code Sample:

static bool Foo<T>()
{
  return typeof(IEnumerable<int>).IsAssignableFrom(typeof(T));
}

Foo<List<T>>();  // true
Foo<int>(); // false
JaredPar
What is the use of int, or was that what you meant by normal type comparison? My List would hold a custom object, but it could be anything as this is used in a Helper function. PS. I tested this code and unfortunately it returned false using int or T.
GONeale
@GONeale, int is just a place holder for the sample code. I verified this code works on my machine when T is List<T> on my machine
JaredPar
Hmm. I am using Intermediate Window now and typeof(IEnumerable<int>).IsAssignableFrom(typeof(T)) is returning false. For ref. T = System.Collections.Generic.List<WcfClientModuleMessageHistory>
GONeale
@GONeal, The immediate window is very different than compiling and running the code. Especially with regards to generics
JaredPar
@Jared, thanks but still no luck. Maybe I should post a complete code sample of what I am trying to do: http://bit.ly/2Bt2jI
GONeale
Thanks for your help Jared. I accepted s_ruchit's answer, I have no idea why yours didn't work, when it clearly looks like it should. Just didn't work with my custom generic list of objects.
GONeale
@GONeal, no worries. You should accept whatever answer helps you the most.
JaredPar
A: 

Also, remember just because you are using generics, don't forget other basic techniques, in this case, like overloading. I suspect the you are planning something like this:

void SomeFunc<T>(T t)
{
    if (IsCollectionCase(t))
       DoSomethingForCollections()
    else
       DoSOmethingElse();
}

This would be far better handled as:

void SomeFunc(IEnumerable t)
{
       DoSomethingForCollections()
}
void SomeFunc<T>(T t)
{
       DoSomethingElse()
}
James Curran
Thanks for the comments James, yep normally I would and an overload would do the trick, but only doing some simple collection adding and private variable changes if it is a list, so no need for any additional function calls. Cheers.
GONeale
+3  A: 

This will be the simplest check..

if(Obj is ICollection)
{
    //Derived from ICollection
}
else
{
    //Not Derived from ICollection
}
this. __curious_geek
So simple. Thanks, using your idea even 'obj is IEnumerable' and 'obj is IList' is working. I had tried 'obj is IEnumerable<T>', 'obj is IList<T>'.. interestingly though that did not work. I have a thought though, T would be a collection. So perhaps it's testing a list of a list somehow *shrug*.
GONeale
@GONeale: Hey this worked for me.List<int> _ints = new List<int>(10); if (_ints is IList<int>) { Console.WriteLine("Yes"); } else { Console.WriteLine("No"); }
this. __curious_geek
**WARNING!** If `obj is ICollection` is true, it **does not follow** that `obj` also implements `ICollection<T>` for any T. The interfaces `ICollection` and `ICollection<T>` are two separate interfaces.
Timwi