Cast from IEnumerable to IEnumerable<object> Cast from IEnumerable to IEnumerable<object> arrays arrays

Cast from IEnumerable to IEnumerable<object>


According to my tests, it works for reference element type but not for value type.

Correct. This is because IEnumerable<out T> is co-variant, and co-variance/contra-variance is not supported for value types.

I come to know that range.Cast() is able to do the job. But it incurs performance overhead which is unnecessary in my opinion.

IMO the performance cost(brought by boxing) is unavoidable if you want a collection of objects with a collection of value-types given. Using the non-generic IEnumerable won't avoid boxing because IEnumerable.GetEnumerator provides a IEnumerator whose .Current property returns an object. I'd prefer always use IEnumerable<T> instead of IEnumerable. So just use the .Cast method and forget the boxing.


After decompiling that extension, the source showed this:

public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)    {      IEnumerable<TResult> enumerable = source as IEnumerable<TResult>;      if (enumerable != null)        return enumerable;      if (source == null)        throw Error.ArgumentNull("source");      return Enumerable.CastIterator<TResult>(source);    }    private static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source)    {      foreach (TResult result in source)        yield return result;    }

This basically does nothing else than IEnumerable<object> in first place.

You stated:

According to my tests, it works for reference element type but not for value type.

How did you test that?


Despite I really do not like this approach, I know it is possible to provide a toolset similar to LINQ-to-Objects that is callable directly on an IEnumerable interface, without forcing a cast to IEnumerable<object> (bad: possible boxing!) and without casting to IEnumerable<TFoo> (even worse: we'd need to know and write TFoo!).

However, it is:

  • not free for runtime: it may be heavy, I didn't run perfomance test
  • not free for developer: you actually need to write all those LINQ-like extension methods for IEnumerable (or find a lib that does it)
  • not simple: you need to inspect the incoming type carefully and need to be careful with many possible options
  • is not an oracle: given a collection that implements IEnumerable but does not implement IEnumerable<T> it only can throw error or silently cast it to IEnumerable<object>
  • will not always work: given a collection that implements both IEnumerable<int> and IEnumerable<string> it simply cannot know what to do; even giving up and casting to IEnumerable<object> doesn't sound right here

Here's an example for .Net4+:

using System;using System.Linq;using System.Collections.Generic;class Program{    public static void Main()    {        Console.WriteLine("List<int>");        new List<int> { 1, 2, 3 }            .DoSomething()            .DoSomething();        Console.WriteLine("List<string>");        new List<string> { "a", "b", "c" }            .DoSomething()            .DoSomething();        Console.WriteLine("int[]");        new int[] { 1, 2, 3 }            .DoSomething()            .DoSomething();        Console.WriteLine("string[]");        new string[] { "a", "b", "c" }            .DoSomething()            .DoSomething();        Console.WriteLine("nongeneric collection with ints");        var stack = new System.Collections.Stack();        stack.Push(1);        stack.Push(2);        stack.Push(3);        stack            .DoSomething()            .DoSomething();        Console.WriteLine("nongeneric collection with mixed items");        new System.Collections.ArrayList { 1, "a", null }            .DoSomething()            .DoSomething();        Console.WriteLine("nongeneric collection with .. bits");        new System.Collections.BitArray(0x6D)            .DoSomething()            .DoSomething();    }}public static class MyGenericUtils{    public static System.Collections.IEnumerable DoSomething(this System.Collections.IEnumerable items)    {        // check the REAL type of incoming collection        // if it implements IEnumerable<T>, we're lucky!        // we can unwrap it        // ...usually. How to unwrap it if it implements it multiple times?!        var ietype = items.GetType().FindInterfaces((t, args) =>            t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>),            null).SingleOrDefault();        if (ietype != null)        {            return                doSomething_X(                    doSomething_X((dynamic)items)                );                // .doSomething_X() - and since the compile-time type is 'dynamic' I cannot chain                // .doSomething_X() - it in normal way (despite the fact it would actually compile well)               // `dynamic` doesn't resolve extension methods!               // it would look for doSomething_X inside the returned object               // ..but that's just INTERNAL implementation. For the user               // on the outside it's chainable        }        else            // uh-oh. no what? it can be array, it can be a non-generic collection            // like System.Collections.Hashtable .. but..            // from the type-definition point of view it means it holds any            // OBJECTs inside, even mixed types, and it exposes them as IEnumerable            // which returns them as OBJECTs, so..            return items.Cast<object>()                .doSomething_X()                .doSomething_X();    }    private static IEnumerable<T> doSomething_X<T>(this IEnumerable<T> valitems)    {        // do-whatever,let's just see it being called        Console.WriteLine("I got <{1}>: {0}", valitems.Count(), typeof(T));        return valitems;    }}

Yes, that's silly. I chained them four (2outsidex2inside) times just to show that the type information is not lost in subsequent calls. The point was to show that the 'entry point' takes a nongeneric IEnumerable and that <T> is resolved wherever it can be. You can easily adapt the code to make it a normal LINQ-to-Objects .Count() method. Similarly, one can write all other operations, too.

This example uses dynamic to let the platform resolve the most-narrow T for IEnumerable, if possible (which we need to ensure first). Without dynamic (i.e. .Net2.0) we'd need to invoke the dosomething_X through reflection, or implement it twice as dosomething_refs<T>():where T:class+dosomething_vals<T>():where T:struct and do some magic to call it properly without actually casting (probably reflection, again).

Nevertheless, it seems that you can get something-like-linq working "directly" on things hidden behind nongeneric IEnumerable. All thanks to the fact that the objects hiding behind IEnumerable still have their own full type information (yeah, that assumption may fail with COM or Remoting). However.. I think settling for IEnumerable<T> is a better option. Let's leave plain old IEnumerable to special cases where there is really no other option.

..oh.. and I actually didn't investigate if the code above is correct, fast, safe, resource-conserving, lazy-evaluating, etc.