4

Perhaps the question title is incorrect. I have the following variables

IEnumerable x = // some IEnumerable
System.Type y = // some type

How can iterate over x in order to generate an array with items of type y?

When I look into the internet I found:

public T[] PerformQuery<T>(IEnumerable q)
{                         
        T[] array = q.Cast<T>().ToArray();
        return array;
}

Note I cannot call that method PerformQuery becuase y is of type System.Type in other words calling it as PerformQuery<typeof(y)>(x); or PerformQuery<y>(x); will give me a compiler error.


edit

Here is the reason why I have that problem. I have web service where I post to it two things. The type of table I will like to query (example typeof(Customer)), and the actual string query example "Select * from customers"

    protected void Page_Load(object sender, EventArgs e)
    {
        // code to deserialize posted data
        Type table = // implement that here
        String query = // the query that was posted

        // note DB is of type DbContext
        IEnumerable q = Db.Database.SqlQuery(table, query );

        // here I will like to cast q to an array of items of type table!
1
  • 3
    Why do you want to do this? Unless you have a known compile-time type, this isn't going to be all that useful (unless I'm missing something). Commented Feb 20, 2014 at 21:46

5 Answers 5

6

You can use Expression Trees:

public static class MyExtensions
{
    public static Array ToArray(this IEnumerable source, Type type)
    {
        var param = Expression.Parameter(typeof(IEnumerable), "source");
        var cast = Expression.Call(typeof(Enumerable), "Cast", new[] { type }, param);
        var toArray = Expression.Call(typeof(Enumerable), "ToArray", new[] { type }, cast);
        var lambda = Expression.Lambda<Func<IEnumerable, Array>>(toArray, param).Compile();

        return lambda(source);
    }
}

It generates x => x.Cast<Type>().ToArray() for you, with Type known at runtime.

Usage:

IEnumerable input = Enumerable.Repeat("test", 10);
Type type = typeof(string);

Array result = input.ToArray(type);
Sign up to request clarification or add additional context in comments.

3 Comments

How is this different from my answer? the Array result is still of unknown type, isn't it? looks like you're overcomplicating it with no extra benefit
+1 thanks a lot. How can I get the inner array of System.Array so that I return an object of type dynamic[] instead of System.Array
You can just cast it to dynamic[]: (dynamic[])result
5
var ObjectsOfType_y = x.OfType<object>().Where(x => x.GetType() == y);

Notice that this will return an IEnumerable<object>, though. There's no way around that because the type that y (Type) represents is unknown at compile time.

1 Comment

How did IEnumerable<object> become an answer for I need T[] question?
0

According to my understanding, IENumerable contains only one type. If I understand what you're trying to do, IENumerable already only contains only objects of type y. If y needs to change, you can write an extension method:

public static T[] ToArray<T>(this IEnumerable<T> source)
    {
        int length = System.Linq.Enumerable.Count(source);
        T[] newArray = new T[length];
        int i = 0;
        foreach(T item in source)
        {
            newArray[i] = item;
        }
        return newArray;
    }

1 Comment

This does not address the original question of casting to a different type using the Type variable at runtime; this only works for generic type parameters at compile time to convert to an array of the exact same type.
0

While the accepted answer here is good and has no dependencies it can have some significant performance impacts as it compiles the expression on every execution.

And if you you are doing reflection operations like this then you should probably be using a nice library like Fasterflect to greatly simplify as well as provide huge performance improvements by encapsulating the complexities of caching, expression building/compiling, etc.

So using Fasterflect this can be done pretty easily with some extension methods such as:

public static class TypeCache
{
    public static readonly Type StringType = typeof(string);
    public static readonly Type EnumerableType = typeof(Enumerable);
}

public static IEnumerable Cast(this IEnumerable source, Type outputType)
    //NOTE: Cast<TResult>() is an extension method that is actually defined on the Enumerable static class which is how we need to reference it...
    => (IEnumerable)TypeCache.EnumerableType.CallMethod(genericTypes: [outputType], name: nameof(Enumerable.Cast), source);

public static Array ToArray(this IEnumerable source, Type outputType)
    => source is not null
        //NOTE: ToArray<TSource>() is an extension method that is actually defined on the Enumerable static class which is how we need to reference it...
        ? (Array)TypeCache.EnumerableType.CallMethod(genericTypes: [outputType], name: nameof(Enumerable.ToArray), source.Cast(outputType))
        : null;

public static IList ToList(this IEnumerable source, Type outputType)
    => source is not null
        //NOTE: ToArray<TSource>() is an extension method that is actually defined on the Enumerable static class which is how we need to reference it...
        ? (IList)TypeCache.EnumerableType.CallMethod(genericTypes: [outputType], name: nameof(Enumerable.ToList), source.Cast(outputType))
        : null;

Usage of this is now very very simple....

//Contrived example where you have two classes MyClass and MySubClass, which inherits from MyClass...
var list = new List<MyClass> { new(1), new(2), new(3) };
var objectEnumerable = (IEnumerable)intList.Select(i => (object)i);

subClassType = typeof(MySubClass);
//Usage
var subClassEnumerable = objectEnumerable.Cast(subClassType);
//or
var subClassArray = objectEnumerable.ToArray(subClassType);
//or
var subClassList = objectEnumerable.ToList(subClassType);

Also available in my Gist here: https://gist.github.com/cajuncoding/c02c5161da146f047df579273cdb4df6

Comments

-1

This is a lot simpler if you use C#'s dynamic dispatch, using the dynamic keyword. You dont even need fancy methods or, even the Type you have. You can directly use your method. So if you have

public T[] PerformQuery<T>(IEnumerable<T> q)
{                         
        T[] array = q.ToArray();
        return array;
}

Just call

IEnumerable x = // some IEnumerable
dynamic y = x;
IEnumerable z = PerformQuery(y);

2 Comments

This does not address the original question of casting to a different type using the Type variable at runtime; this only works for generic type parameters at compile time to convert to an array of the exact same type.
This does address the exact problem OP is facing, which is not being able to call PerformQuery method because it is generic. If you want to cast to a different type (like you say), which is not the question, then that depends on your definition of casting. Representation changing casting can be done (with methods like ConvertType though it is a very different thing). OP merely wants a representation preserving casting (where he doesnt know the type at compile time).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.