与Queryable.Select使用Expression.Call只在运行时已知的类型(Using

2019-09-19 01:23发布

我想从清单中选择一列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的表达,我认为将代表拉姆达我通常会通过选择(假设我试图执行上述同样的操作,有字符串和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)

现在希望所有剩下的就是建立是调用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#中的例子)

Answer 1:

 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);

这是使用表达式的答案,基本上我们处理每件事情都作为对象(铸造我们的运行时类型,然后铸造回对象的最终结果。



文章来源: Using Expression.Call with Queryable.Select with a type known only at runtime