我试图从IEnumerable
集合中选择一个只有我在运行时才知道的类型的列。我能想到的唯一方法是使用LINQ表达式来构建一个动态调用Queryable.Select
。但是,我很难找出正确的语法来完成这个任务。使用Expression.Call 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表达式,我相信它将表示我通常会选择的lambda表达式(假设我正尝试使用String和String执行上面的相同操作。长度)
' 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)
现在希望所有的左边是构建是调用Queryable.Select
。对我来说,Expression.Call的语法至少可以说是令人困惑的。我尝试如下(其中失败,没有任何形式的错误或解释):
' Creates a Parameter Expression of type IQueryable(Of String)
Dim source = Expression.Parameter(GetType(IQueryable(Of)).MakeGenericType(pi.DeclaringType), "source")
' Ideally, this would create an expression for a call to Queryable.Select
Dim selectCall = Expression.Call(GetType(Queryable), "Select", {pi.DeclaringType, pi.PropertyType}, source)
我试图以另一种方式,而不使用类型做这个[]参数,并使用我的项目和属性来表达无效:
Dim alternateExp = Expression.Call(GetType(Queryable), "Select", Nothing, {targetProperty, item})
问题是,我几乎只是猜测在这一点上。但是,构建函数调用,何时使用类型或表达式,使用哪些类型或表达式,甚至何处使用它们的整个想法都很简单。任何帮助让我走到那里的最后一部分,并清除一些这个谜,将不胜感激。 (我非常高兴在C#示例)
谢谢,完美的工作!它甚至不需要使用令人困惑的Expression.Call。希望我可以扩展它来执行其他操作,例如分组。 – mclark1129