0

Adopting the reply on Combine several similar SELECT-expressions into a single expression

I had adapted the code as below and works fine..

But I would do like to work with expressions like

Expression<Func<Agency, object>> selector1 = x => new { Name = x.Name };

instead of

Expression<Func<Agency, AgencyDTO>> selector1 = x => new AgencyDTO { Name = x.Name };

How can I get it working with such anonymous types?

This code (MemberInitExpression)selector.Body breaks if anonymous types is used

---- current code ---

public static class SelectBuilder
{

     public static IQueryable<object> SelectExtend<TSource>(this IQueryable<TSource> queryable, params Expression<Func<TSource, object>>[] selectors) => queryable.Select(Combine(selectors)); //Won't work

    public static IQueryable<TResult> SelectExtend<TSource, TResult>(this IQueryable<TSource> queryable, params Expression<Func<TSource, TResult>>[] selectors) => queryable.Select(Combine(selectors));

    private static Expression<Func<TSource, TDestination>> Combine<TSource, TDestination>(params Expression<Func<TSource, TDestination>>[] selectors)
    {
        var expression = Expression.Parameter(typeof(TSource), "s");
        return Expression.Lambda<Func<TSource, TDestination>>(
            Expression.MemberInit(
                Expression.New(typeof(TDestination).GetConstructor(Type.EmptyTypes) ?? throw new InvalidOperationException()), selectors.Select(selector => new
                {
                    selector,
                    replace = new ParameterVisitorReplacer(selector.Parameters[0], expression)
                })
                    .SelectMany(t => ((MemberInitExpression)t.selector.Body).Bindings.OfType<MemberAssignment>(), (t, binding) => Expression.Bind(binding.Member, t.replace.VisitAndConvert(binding.Expression, "Combine") ?? throw new InvalidOperationException()))), expression);
    }

    private sealed class ParameterVisitorReplacer : ExpressionVisitor
    {
        private readonly ParameterExpression _to;
        private readonly ParameterExpression _from;

        public ParameterVisitorReplacer(ParameterExpression from, ParameterExpression to)
        {
            _to = to;
            _from = from;
        }

        protected override Expression VisitParameter(ParameterExpression node) => node == _from ? _to : base.VisitParameter(node);
    }

}
alhpe
  • 1,424
  • 18
  • 24
  • Could you please explain how do you plan to use that `IQueryable`? You will not be able to cast it items to regular type. I'm asking because I'm not sure that solution I can offer will satisfy your needs – Aleks Andreev Mar 29 '19 at 11:43
  • I plant to use it as par of a EF Core Select clause like: var data = context.Set().Select(selector).ToArray(); but the selector expresion I would do like to be composable or buit dynamically from an array or anonymous expresion. – alhpe Mar 29 '19 at 19:41
  • I plant to use it as part of a EF Core Select() clause like: var data = context.Set().Select(selector).ToArray(); but the selector expression I would do like to be built dynamically from an array or anonymous expressions. i.e having Expression> idSelector = p => new { p.Id, } and Expression> nameSelector = p => new { p.FirstName, }; compose from those Expression> composedSelector = p => new { p.Id, FirstName }; for usage on the Select() clause – alhpe Mar 29 '19 at 19:47
  • That's because `t.selector.Body` for an anonymous type lambda is not a `MemberInitExpression`. Using LINQPad, you can `Dump` an example `Expression` and see it is instead a `NewExpression` with `Arguments` and `Members` and a `Constructor`. The problem is you won't have an anonymous class to return unless you create one dynamically, which isn't easy. – NetMage Mar 29 '19 at 20:24
  • I thinks is not possible to do it since the expressions are anonymous types expressions.. any ideas? – alhpe Apr 01 '19 at 12:04
  • It is possible, just difficult and of questionable utility (you have an anonymous object, but you don't know its type at compile time, so you can't use the results). Think about how you want to use the result of the combined `Select` and that might point you in the right direction. – NetMage Apr 01 '19 at 20:25
  • I would do like to compose at run time such an anonymous object to use it on a E.F. Core select projection – alhpe Apr 02 '19 at 23:28

0 Answers0