Объединить несколько похожих выражений SELECT-выражений <Func <T, object >> в одно выражение - PullRequest
0 голосов
/ 29 марта 2019

Принятие ответа на Объединение нескольких похожих выражений SELECT в одно выражение

Я адаптировал код, как показано ниже, и работает нормально ..

Но я бы хотел работать с такими выражениями, как

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

вместо

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

Как мне заставить его работать с такими анонимными типами?

Этот код (MemberInitExpression)selector.Body ломается, если используются анонимные типы

---- текущий код ---

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

}
...