61

I have a class (A web control) that has a property of type IEnumerable and would like to work with the parameter using LINQ.

Is there any way to cast / convert / invoke via reflection to IEnumerable<T> not knowing the type at compile time?

Method void (IEnumerable source)
{
    var enumerator = source.GetEnumerator();

    if (enumerator.MoveNext())
    {
        var type = enumerator.Current.GetType();
        Method2<type>(source); // this doesn't work! I know!
    }
}

void Method2<T>(IEnumerable<T> source) {}
andleer
  • 22,388
  • 8
  • 62
  • 82

4 Answers4

76

Does your Method2 really care what type it gets? If not, you could just call Cast<object>():

void Method (IEnumerable source)
{
    Method2(source.Cast<object>());
}

If you definitely need to get the right type, you'll need to use reflection.

Something like:

MethodInfo method = typeof(MyType).GetMethod("Method2");
MethodInfo generic = method.MakeGenericMethod(type);
generic.Invoke(this, new object[] {source});

It's not ideal though... in particular, if source isn't exactly an IEnumerable<type> then the invocation will fail. For instance, if the first element happens to be a string, but source is a List<object>, you'll have problems.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Depending on the situation you can also use `OfType`, just pointing out. See also: http://stackoverflow.com/questions/4015930/when-to-use-cast-and-oftype-in-linq – Alvin Wong Sep 25 '13 at 14:15
  • This is also an approach for moving from IQueryable to IQueryable (applicable to other such scenarios.) Once you get moved over, you'll be able to call and use all the things you expect and need without fail. – Greg Mar 17 '19 at 00:38
11

You probably want to refactor your code to use IEnumerable.Cast<T>

Use it like this:

IEnumerable mySet = GetData();
var query = from x in mySet.Cast<int>()
            where x > 2
            select x;
Brian Genisio
  • 47,787
  • 16
  • 124
  • 167
5

With .NET 4 you can just cast source to dynamic before passing it to method. This will cause the correct generic overload to be resolved at runtime without any ugly reflection code:

void Method(IEnumerable source)
{
    var enumerator = source.GetEnumerator();

    if (enumerator.MoveNext())
    {
        Method2((dynamic)source);
    }
}

As with Jon's second solution, this will only work if your source is actually an IEnumerable<T>. If it is a plain IEnumerable then you'll need to create another method that converts it to the correct IEnumerable<T> type, as in the following solution:

IEnumerable<T> Convert<T>(IEnumerable source, T firstItem)
{
    // Note: firstItem parameter is unused and is just for resolving type of T
    foreach(var item in source)
    {
        yield return (T)item;
    }
}

void Method(IEnumerable source)
{
    var enumerator = source.GetEnumerator();

    if (enumerator.MoveNext())
    {
        dynamic firstItem = enumerator.Current;
        dynamic typedEnumerable = Convert(source, firstItem);
        Method2(typedEnumerable);
    }
}
luksan
  • 7,661
  • 3
  • 36
  • 38
2

This is years later, but I solved the List<Object> problem.

void Method(IEnumerable source)
{
    var enumerator = source.GetEnumerator();
    if (enumerator.MoveNext())
    {
        MethodInfo method = typeof(MyClass).GetMethod("Method2");
        MethodInfo generic;
        Type type = enumerator.Current.GetType();
        bool sameType = true;

        while (enumerator.MoveNext())
        {
            if (enumerator.Current.GetType() != type)
            {
                sameType = false;
                break;
            }
        }

        if (sameType)
            generic = method.MakeGenericMethod(type);
        else
            generic = method.MakeGenericMethod(typeof(object));

        generic.Invoke(this, new object[] { source });
    }
}