.net 使用Expression.Call和Queryable。使用仅在运行时已知的类型进行选择

.net 使用Expression.Call和Queryable。使用仅在运行时已知的类型进行选择,.net,vb.net,reflection,iqueryable,linq-expressions,.net,Vb.net,Reflection,Iqueryable,Linq Expressions,我试图从IEnumerable集合中选择一列,该集合的类型在运行时只有我知道。我能想到的唯一方法是使用LINQ表达式来构建对Queryable.Select的动态调用。然而,我很难找到正确的语法来完成这项任务 在编译时知道所有需要的东西的幸运世界中,我将如何做到这一点,我的代码如下所示: ' Create an IEnumerable(Of String) Dim strings = { "one", "two", "three" } ' Produce a collection with e

我试图从IEnumerable集合中选择一列,该集合的类型在运行时只有我知道。我能想到的唯一方法是使用LINQ表达式来构建对Queryable.Select的动态调用。然而,我很难找到正确的语法来完成这项任务

在编译时知道所有需要的东西的幸运世界中,我将如何做到这一点,我的代码如下所示:

' Create an IEnumerable(Of String)
Dim strings = { "one", "two", "three" }

' Produce a collection with elements {3,3,5}
Dim stringLengths = strings.Select(Function(x) x.Length)
不幸的是,实际上,我不知道我拥有的集合是String类型的,或者我想要选择的属性是Length。我所拥有的是一个IEnumerable项集合,以及我要选择的列的PropertyInfo,它提供了我所需的所有类型信息

就表达式而言,我已经能够创建一个LINQ表达式,我相信它将表示我通常传递给select的lambda,假设我正在尝试使用String和String.Length执行上述相同的操作

' pi is the PropertyInfo containing the Length property I am trying to select.
' pi.DeclaringType is String and pi.Name is Length
Dim targetItem = Expression.Parameter(pi.DeclaringType, "x")
Dim targetProperty = Expression.Property(targetItem, pi.Name)

' Produces the lambda<Function(x) x.Length>
Dim selectLambda = Expression.Lambda(targetProperty, targetItem)
我尝试以另一种方式执行此操作,但没有使用Type[]参数,也没有为我的项和属性使用表达式,但没有效果:

Dim alternateExp = Expression.Call(GetType(Queryable), "Select", Nothing, {targetProperty, item})
问题是,我只是在这一点上猜测。然而,构建函数调用、何时使用类型或表达式、使用哪种类型或表达式、甚至在何处使用它们的整个想法都很混乱。如果有人能帮我找到最后一段路并解开一些谜团,我将不胜感激。我对C语言中的例子非常满意

 var propertyType = typeof (string);
 var propertyName = "Length";
 IEnumerable list = new ArrayList { "one", "two", "three" };


  var item = Expression.Parameter(typeof(object), "x");
  var cast = Expression.Convert(item, propertyType);
  var propertyValue = Expression.PropertyOrField(cast, propertyName);
  var propertyValueAsObject = Expression.Convert(propertyValue, typeof (object));
  var selectLambda = Expression.Lambda<Func<object, object>>(propertyValueAsObject, item);

  list.Cast<object>().AsQueryable().Select(selectLambda);
这是一个使用表达式的答案,基本上我们将所有内容作为一个对象来处理,并将其转换为运行时类型,然后再转换回对象以获得最终结果


这是一个使用表达式的答案,基本上我们将所有内容都作为一个对象来处理,转换为我们的运行时类型,然后再转换回对象以获得最终结果。

谢谢,这非常有效!它甚至不需要使用令人困惑的表达式.Call。希望我能够在此基础上扩展以执行其他操作,例如分组。谢谢,这非常有效!它甚至不需要使用令人困惑的表达式.Call。希望我能够在此基础上进行扩展,以执行其他操作,例如分组。
 var propertyType = typeof (string);
 var propertyName = "Length";
 IEnumerable list = new ArrayList { "one", "two", "three" };


  var item = Expression.Parameter(typeof(object), "x");
  var cast = Expression.Convert(item, propertyType);
  var propertyValue = Expression.PropertyOrField(cast, propertyName);
  var propertyValueAsObject = Expression.Convert(propertyValue, typeof (object));
  var selectLambda = Expression.Lambda<Func<object, object>>(propertyValueAsObject, item);

  list.Cast<object>().AsQueryable().Select(selectLambda);