public override object VisitSelectExpression(QueryFilteringParser.SelectExpressionContext context) { var properties = context.PROPERTYACCESS() .Select(x => x.Symbol.Text) .ToHashSet(); var typeProperties = _parameter.Type .GetCashedProperties() .Where(p => properties.Contains(p.Name)) .ToDictionary(p => p.Name, p => p.PropertyType); var dynamicType = DynamicTypeBuilder.CreateDynamicType(typeProperties); var propExpressions = properties.ToDictionary(x => x, x => new PropertyNode(x, _parameter).CreateExpression()); var body = Expression.MemberInit( Expression.New(dynamicType.GetConstructors().Single()), dynamicType.GetFields().Select(f => Expression.Bind(f, propExpressions[f.Name]))); var lambda = ReflectionCache.Lambda.MakeGenericMethod( typeof(Func <,>).MakeGenericType(_parameter.Type, dynamicType)); var expression = lambda.Invoke(null, new object[] { body, new ParameterExpression[] { _parameter } }); var select = ReflectionCache.Select .MakeGenericMethod(_parameter.Type, dynamicType); return(select.Invoke(null, new [] { _sourceQueryable, expression })); }
/// <summary> /// Visit a parse tree produced by <see cref="QueryFilteringParser.selectExpression"/>. /// <para> /// The default implementation returns the result of calling <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/> /// on <paramref name="context"/>. /// </para> /// </summary> /// <param name="context">The parse tree.</param> /// <return>The visitor result.</return> public virtual Result VisitSelectExpression([NotNull] QueryFilteringParser.SelectExpressionContext context) { return(VisitChildren(context)); }