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