Question

I'm querying a data structure and the result type is IEnumerable<IEntry> (IEntry being a framework interface), each entry has a Data property (of type object) which is interseting for me.

My code looks like this:

var resultList = framework.QueryAllOfType(queryClause.Type)
                          .Select(e => e.Data)
                          .ToList();
deleagte.DynamicInvoke(new[]{resultList});

The method behind the delegate looks something like this:

void Foo (IEnumerable<SomeType> bar); // if queryClause.Type == typeof(SomeType)
void Foo (IEnumerable<OtherType> bar); // if queryClause.Type == typeof(OtherType)

I'm absolutely positive that queryClause.Type matches SomeType, of course however, the .NET framework is not ;-)

Unfortunately this means that the resultList is of type IEnumerable<object> although all the objects within are of the correct type, I'm not able to call the delegate (exception: IEnumerable<object> cannot be converted into IEnumerable<SomeType>).

I know why this is the case, but what's the solution? I would need something along the lines of:

.Select(e => e.Data).Cast(queryClause.Type).ToList() which should return an IEnumerable<queryClause.Type>. Is there such a thing already somewhere in the .NET framework? Is there a better solution?

Important: As two answers already misunderstood my intensions, I cannot use the type as a generic parameter as it is known at runtime only. Therefore all Cast<...>(), Select(e =e as ...), etc. do not work.

Was it helpful?

Solution

You can invoke Cast using reflection:

var method = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(queryClause.Type);
IEnumerable<object> cSeq = (IEnumerable<object>)method.Invoke(null, new object[] { resultList });

deleagte.DynamicInvoke(new[]{ cSeq });

OTHER TIPS

Base on your feedback and using the other answers I've created a ToListOfType() extension method that should do what you need.

public static class EnumerableExtensions
{
    private static readonly Type _enumerableType = typeof(Enumerable);

    public static IEnumerable CastAsType(this IEnumerable source, Type targetType)
    {
        var castMethod = _enumerableType.GetMethod("Cast").MakeGenericMethod(targetType);

        return (IEnumerable)castMethod.Invoke(null, new object[] { source });
    } 

    public static IList ToListOfType(this IEnumerable source, Type targetType)
    {
        var enumerable = CastAsType(source, targetType);

        var listMethod = _enumerableType.GetMethod("ToList").MakeGenericMethod(targetType);

        return (IList)listMethod.Invoke(null, new object[] { enumerable });
    } 
}

This should work with your delegate if you simply replace your ToList() call with ToListOfType(queryClause.Type). I implemented both the CastAsType and ToListOfType methods so that you can leave the collection un-iterated if you so choose. I'll note for future readers that these are only useful in a situation like yours where you're passing the result off to a delegate dynamically - the Cast<T> operation would be preferred in all other cases.

Try to finish with something like:

.ToList<IEntry>()

is like for example if you do something like:

int[] text = {01, 2, 3, 4, 5};

List<string> list = text.Select(x => x.ToString()).ToList<string>();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top