使用防爆pression.Call与Queryable.Select有只知道在运行时类型只知道、类型、Call、pression

2023-09-06 17:27:22 作者:ら粪飛的ㄖΖ,笑看落埖ら

我想选择从的IEnumerable 收集有只知道我在运行时类型的列。我能想到用这个的唯一方法是使用LINQ EX pressions建立一个动态调用 Queryable.Select 。不过,我有一个很大的麻烦找出正确的语法来做到这一点。

的我怎么会在明知一切,我需要在编译时的快乐去,幸运的世界做这方面的例子,我的code是这样的:

 '创建一个IEnumerable(串)
昏暗的字符串= {一,二,三}

生产出的元素集合{3,3,5}
昏暗stringLengths = strings.Select(功能(X)x.Length)
 

不幸的是,在现实中,我不知道该集合我已经是类型字符串,或者说我要选择的属性是。我要做的已经是一个的IEnumerable 集合的项目,以及一个的PropertyInfo 我要选择的列它提供了我所有我需要的那种类型的信息。

据EX pressions走了,我已经能够创建一个LINQ EX pression,我相信会重新present拉姆达我通常会通过选择(假设我想执行相同的操作上面,用字符串和string.length减)

 圆周率是包含Length属性我想选择的PropertyInfo。
pi.DeclaringType为String和pi.Name是长
暗淡targetItem =实施例pression.Parameter(pi.DeclaringType,×)
昏暗targetProperty =前pression.Property(targetItem,pi.Name)

生产拉姆达<作用(X)x.Length>
昏暗selectLambda =前pression.Lambda(targetProperty,targetItem)
 

现在希望所有的左边是构建是调用 Queryable.Select 。对我来说,前pression.Call的语法为pretty的混乱,至少可以说。我尝试如下(其中失败,无任何错误或任何形式的解释):

 创建类型的参数e pression的IQueryable(串)
昏暗源=前pression.Parameter(的GetType(IQueryable的()。中)MakeGenericType(pi.DeclaringType),源)

理想情况下,这将创建一个EX pression的调用Queryable.Select
昏暗的selectCall =前pression.Call(的GetType(可查询),选择,{pi.DeclaringType,pi.PropertyType},源)
 
iOS对象的底层探索 上

我试着不使用类型[]参数,使用前pressions我的物品和财产也没有用另一种方式这样做:

 暗淡alternateExp =前pression.Call(的GetType(可查询),选择,没什么,{targetProperty,项目})
 

现在的问题是,我是pretty的多少只是猜测在这一点上。然而,建立函数调用,何时使用类型或防爆pressions,类型或EX pressions要使用的,或者甚至使用它们的整体思路是只是普通的困惑。任何帮助,让我的方法的最后部分还有和清除一些这奥秘将大大AP preciated。 (我完全满意,在C#中的例子)

解决方案

  VAR属性类型= ty​​peof运算(字符串);
 变种propertyName的=长度;
 IEnumerable的名单=新的ArrayList {一,二,三};


  变种项=实施例pression.Parameter(typeof运算(对象),×);
  VAR投=前pression.Convert(项目,属性类型);
  VAR为PropertyValue =前pression.PropertyOrField(铸,propertyName的);
  VAR propertyValueAsObject =前pression.Convert(为PropertyValue的typeof(对象));
  VAR selectLambda =前pression.Lambda< Func键<对象,对象>>(propertyValueAsObject,项目);

  list.Cast<对象>()AsQueryable已()选择(selectLambda)。
 

这是使用前pressions答案,基本上我们对待每件事情都作为对象(铸造到我们的运行时类型,然后浇注回对象的最终结果。

I am trying to select a column from an IEnumerable collection that has a type known only to me at runtime. The only way I can think of using this is using LINQ expressions to build a dynamic call to Queryable.Select. However, I'm having a lot of trouble figuring out the proper syntax to accomplish this.

An example of how I would do this in the happy-go-lucky world of knowing everything I need at compile time, my code would look like this:

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

Unfortunately, in reality I have no idea that the collection I have is of type String, or that the property I want to select is Length. What I do have is an IEnumerable collection of items, as well as a PropertyInfo of the column that I want to select which provides me all of the type information I need.

As far as expressions go, I've been able to create a LINQ expression that I believe would represent the lambda I would normally pass to select ( Assume I am trying to perform the same operation above, with String and 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)

Now hopefully all that's left is to build is the call to Queryable.Select. To me, the syntax of Expression.Call is pretty confusing to say the least. My attempt is as follows (which fails with no errors or explanation of any kind):

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

I tried doing this in an alternative way without using the Type[] parameter and using the expressions for my item and property to no avail:

Dim alternateExp = Expression.Call(GetType(Queryable), "Select", Nothing, {targetProperty, item})

The problem is that I'm pretty much just guessing at this point. However, the whole idea of building the function call, when to use Types or Expressions, which types or expressions to use, or where to even use them is just plain confusing. Any help getting me the last part of the way there and clearing some of this mystery would be greatly appreciated. (I'm perfectly happy with examples in 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);

This is an answer using expressions, basically we deal with everything as an Object (casting to our runtime type and then casting back to Object for the final result.