将IEnumerable转换为T[]数组

3
也许问题标题不正确。我有以下变量。
IEnumerable x = // some IEnumerable
System.Type y = // some type

如何迭代x以生成类型为y的数组?

当我查看互联网时,我发现:

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

注意,我无法调用PerformQuery方法,因为变量y是一个System.Type类型。换句话说,使用PerformQuery(x)或PerformQuery(x)会报编译错误。
编辑:
我遇到这个问题的原因是:我有一个web服务,在其中发送两个参数。一个是我想查询的表的类型(例如 typeof(Customer)),另一个是实际的查询字符串,例如“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!

3
为什么你想这样做?除非你有已知的编译时类型,否则这并没有太大用处(除非我漏掉了什么)。 - spender
4个回答

6
您可以使用表达式树:
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);
    }
}

它会生成 x => x.Cast<Type>().ToArray() ,并且在运行时知道Type

用法:

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

Array result = input.ToArray(type);

这与我的答案有何不同?Array result仍然是未知类型,不是吗?看起来你过于复杂化了,没有额外的好处。 - Federico Berasategui
+1 非常感谢。我该如何获取 System.Array 的内部数组,以便返回类型为 dynamic[] 的对象,而不是 System.Array - Tono Nam
你可以将其强制转换为 dynamic[](dynamic[])result - MarcinJuraszek

5
var ObjectsOfType_y = x.OfType<object>().Where(x => x.GetType() == y);

请注意,这将返回一个 IEnumerable<object>。由于 y(类型)所代表的类型在编译时是未知的,因此没有任何方法可以解决这个问题。


2
IEnumerable<object>如何成为“I need T[]”问题的答案? - MarcinJuraszek

0
根据我的理解,IENumerable只包含一种类型。如果我正确理解您的意图,IENumerable已经仅包含类型为y的对象。如果需要更改y,则可以编写扩展方法:
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;
    }

0

如果你使用C#的动态分派,使用dynamic关键字,这会简单得多。你甚至不需要复杂的方法或者Type。你可以直接使用你的方法。所以,如果你有:

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

只需调用

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接