Я пытаюсь выбрать столбец из коллекции 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, которое, как мне кажется, будет представлять лямбду, которую я обычно передаю для выбора (предположим, я пытаюсь выполнить ту же операцию, что и выше, со строкой и строкой.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)
Я попытался сделать это альтернативным способом, не используя параметр Type[] и используя выражения для моего элемента и свойства, но безрезультатно:
Dim alternateExp = Expression.Call(GetType(Queryable), "Select", Nothing, {targetProperty, item})
Проблема в том, что я в значительной степени только предполагаю на данный момент. Однако вся идея создания вызова функции, когда использовать типы или выражения, какие типы или выражения использовать или даже где их использовать, просто сбивает с толку. Буду очень признателен за любую помощь, которая поможет мне пройти последнюю часть пути и прояснить часть этой тайны. (я вполне доволен примерами на С#)