Принятие ответа на Объединение нескольких похожих выражений 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);
}
}