100

I have a class that implements IEnumerable, but doesn't implement IEnumerable<T>. I can't change this class, and I can't use another class instead of it. As I've understood from MSDN LINQ can be used if class implements IEnumerable<T>. I've tried using instance.ToQueryable(), but it still doesn't enable LINQ methods. I know for sure that this class can contain instances of only one type, so the class could implement IEnumerable<T>, but it just doesn't. So what can I do to query this class using LINQ expressions?

Ben L
  • 1,302
  • 11
  • 23
Bogdan Verbenets
  • 25,686
  • 13
  • 66
  • 119
  • Without casting the IEnumerable, instead of the all the linq methods you'll only see 8 methods: AsQueryable, Cast<>, Equals, GetEnumerator, GetHashCode, GetType, OfType<>, ToString – ShawnFeatherly Jan 31 '13 at 21:52

3 Answers3

153

You can use Cast<T>() or OfType<T> to get a generic version of an IEnumerable that fully supports LINQ.

Eg.

IEnumerable objects = ...;
IEnumerable<string> strings = objects.Cast<string>();

Or if you don't know what type it contains you can always do:

IEnumerable<object> e = objects.Cast<object>();

If your non-generic IEnumerable contains objects of various types and you are only interested in eg. the strings you can do:

IEnumerable<string> strings = objects.OfType<string>();
DeCaf
  • 6,026
  • 1
  • 29
  • 51
14

Yes it can. You just need to use the Cast<T> function to get it converted to a typed IEnumerable<T>. For example:

IEnumerable e = ...;
IEnumerable<object> e2 = e.Cast<object>();

Now e2 is an IEnumerable<T> and can work with all LINQ functions.

Mike Lowery
  • 2,630
  • 4
  • 34
  • 44
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
4

You can also use LINQ's query comprehension syntax, which casts to the type of the range variable (item in this example) if a type is specified:

IEnumerable list = new ArrayList { "dog", "cat" };

IEnumerable<string> result =
  from string item in list
  select item;

foreach (string s in result)
{
    // InvalidCastException at runtime if element is not a string

    Console.WriteLine(s);
}

The effect is identical to @JaredPar's solution; see 7.16.2.2: Explicit Range Variable Types in the C# language specification for details.

TrueWill
  • 25,132
  • 10
  • 101
  • 150